From 32db3ad86bcf04e4f34705a396b718061d333f20 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 10 Mar 2009 16:14:11 +0000 Subject: merge webpay support in with autoselection of old realtime_bop and realtime_refund_bop --- FS/FS/ClientAPI/MyAccount.pm | 35 + FS/FS/ClientAPI/Signup.pm | 141 +- FS/FS/Conf.pm | 12 + FS/FS/Schema.pm | 4 + FS/FS/agent.pm | 102 ++ FS/FS/cust_main.pm | 1410 ++++++++++++++++++-- FS/FS/cust_pay_pending.pm | 13 + FS/FS/cust_pkg.pm | 4 +- FS/FS/payby.pm | 15 + FS/FS/payment_gateway.pm | 49 +- fs_selfservice/FS-SelfService/SelfService.pm | 2 + fs_selfservice/FS-SelfService/cgi/change_pay.html | 3 +- .../cgi/make_thirdparty_payment.html | 38 + fs_selfservice/FS-SelfService/cgi/myaccount.html | 6 +- .../FS-SelfService/cgi/myaccount_menu.html | 36 +- fs_selfservice/FS-SelfService/cgi/selfservice.cgi | 11 +- fs_selfservice/FS-SelfService/cgi/signup.cgi | 97 +- fs_selfservice/FS-SelfService/cgi/signup.html | 2 +- fs_selfservice/FS-SelfService/cgi/verify.cgi | 175 +++ httemplate/browse/payment_gateway.html | 4 + httemplate/edit/payment_gateway.html | 232 ++-- httemplate/edit/process/payment_gateway.html | 39 +- httemplate/elements/tr-textarea.html | 25 + 23 files changed, 2169 insertions(+), 286 deletions(-) create mode 100755 fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html create mode 100755 fs_selfservice/FS-SelfService/cgi/verify.cgi create mode 100644 httemplate/elements/tr-textarea.html diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index c0586af00..c6a4e0058 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -353,6 +353,9 @@ sub payment_info { 'paytypes' => [ @FS::cust_main::paytypes ], 'paybys' => [ $conf->config('signup_server-payby') ], + 'cust_paybys' => [ map { FS::payby->payby2payment($_) } + $conf->config('signup_server-payby') + ], 'stateid_label' => FS::Msgcat::_gettext('stateid'), 'stateid_state_label' => FS::Msgcat::_gettext('stateid_state'), @@ -375,6 +378,18 @@ sub payment_info { my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; + $return{hide_payment_fields} = + [ + map { FS::payby->realtime($_) && + $cust_main + ->agent + ->payment_gateway( 'method' => FS::payby->payby2bop($_) ) + ->gateway_namespace + eq 'Business::OnlineThirdPartyPayment' + } + @{ $return{cust_paybys} } + ]; + $return{balance} = $cust_main->balance; $return{payname} = $cust_main->payname @@ -531,6 +546,26 @@ sub process_payment { } +sub realtime_collect { + + my $p = shift; + + my $session = _cache->get($p->{'session_id'}) + or return { 'error' => "Can't resume session" }; #better error message + + my $custnum = $session->{'custnum'}; + + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or return { 'error' => "unknown custnum $custnum" }; + + my $error = $cust_main->realtime_collect( 'method' => $p->{'method'}, + 'session_id' => $p->{'session_id'}, + ); + return { 'error' => $error } unless ref( $error ); + + return { 'error' => '', amount => $cust_main->balance, %$error }; +} + sub process_payment_order_pkg { my $p = shift; diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm index 5569dfbde..02aa5800b 100644 --- a/FS/FS/ClientAPI/Signup.pm +++ b/FS/FS/ClientAPI/Signup.pm @@ -6,6 +6,7 @@ use Data::Dumper; use Tie::RefHash; use FS::Conf; use FS::Record qw(qsearch qsearchs dbdef); +use FS::CGI qw(popurl); use FS::Msgcat qw(gettext); use FS::Misc qw(card_types); use FS::ClientAPI_SessionCache; @@ -20,6 +21,7 @@ use FS::svc_phone; use FS::acct_snarf; use FS::queue; use FS::reg_code; +use FS::payby; $DEBUG = 0; $me = '[FS::ClientAPI::Signup]'; @@ -276,6 +278,29 @@ sub signup_info { if ( $agentnum ) { + warn "$me setting agent-specific payment flag\n" if $DEBUG > 1; + my $agent = qsearchs('agent', { 'agentnum' => $agentnum } ); + warn "$me has agent $agent\n" if $DEBUG > 1; + if ( $agent ) { #else complain loudly? + $signup_info->{'hide_payment_fields'} = []; + foreach my $payby (@{$signup_info->{payby}}) { + warn "$me checking $payby payment fields\n" if $DEBUG > 1; + my $hide = 0; + if (FS::payby->realtime($payby)) { + my $payment_gateway = + $agent->payment_gateway( 'method' => FS::payby->payby2bop($payby) ); + if ($payment_gateway->gateway_namespace eq + 'Business::OnlineThirdPartyPayment' + ) { + warn "$me hiding $payby payment fields\n" if $DEBUG > 1; + $hide = 1; + } + } + push @{$signup_info->{'hide_payment_fields'}}, $hide; + } + } + warn "$me done setting agent-specific payment flag\n" if $DEBUG > 1; + warn "$me setting agent-specific package list\n" if $DEBUG > 1; $signup_info->{'part_pkg'} = $signup_info->{'agentnum2part_pkg'}{$agentnum} unless @{ $signup_info->{'part_pkg'} }; @@ -295,8 +320,6 @@ sub signup_info { ]; warn "$me done setting agent-specific adv. source list\n" if $DEBUG > 1; - my $agent = qsearchs('agent', { 'agentnum' => $agentnum } ); - $signup_info->{'agent_name'} = $agent->agent; $signup_info->{'company_name'} = $conf->config('company_name', $agentnum); @@ -436,6 +459,23 @@ sub new_customer { unless grep { $_ eq $packet->{'payby'} } $conf->config('signup_server-payby'); + if (FS::payby->realtime($packet->{payby})) { + my $payby = $packet->{payby}; + + my $agent = qsearchs('agent', { 'agentnum' => $agentnum }); + return { 'error' => "Unknown reseller" } + unless $agent; + + my $payment_gateway = + $agent->payment_gateway( 'method' => FS::payby->payby2bop($payby) ); + + if ($payment_gateway->gateway_namespace eq + 'Business::OnlineThirdPartyPayment' + ) { + $cust_main->payby('BILL'); # MCRD better? + } + } + $cust_main->payinfo($cust_main->daytime) if $cust_main->payby eq 'LECB' && ! $cust_main->payinfo; @@ -547,10 +587,26 @@ sub new_customer { # " new customer: $bill_error" # if $bill_error; - $bill_error = $cust_main->collect('realtime' => 1); + if ($cust_main->_new_bop_required()) { + $bill_error = $cust_main->realtime_collect( + method => FS::payby->payby2bop( $packet->{payby} ), + depend_jobnum => $placeholder->jobnum, + ); + } else { + $bill_error = $cust_main->collect('realtime' => 1); + } #warn "[fs_signup_server] error collecting from new customer: $bill_error" # if $bill_error; + if ($bill_error && ref($bill_error) eq 'HASH') { + return { 'error' => '_collect', + ( map { $_ => $bill_error->{$_} } + qw(popup_url reference collectitems) + ), + amount => $cust_main->balance, + }; + } + if ( $cust_main->balance > 0 ) { #this makes sense. credit is "un-doing" the invoice @@ -600,4 +656,83 @@ sub new_customer { } +sub capture_payment { + my $packet = shift; + + warn "$me capture_payment called on $packet\n" if $DEBUG; + + ### + # identify processor/gateway from called back URL + ### + + my $conf = new FS::Conf; + + my $url = $packet->{url}; + my $payment_gateway = + qsearchs('payment_gateway', { 'gateway_callback_url' => popurl(0, $url) } ); + + unless ($payment_gateway) { + + my ( $processor, $login, $password, $action, @bop_options ) = + $conf->config('business-onlinepayment'); + $action ||= 'normal authorization'; + pop @bop_options if scalar(@bop_options) % 2 && $bop_options[-1] =~ /^\s*$/; + die "No real-time processor is enabled - ". + "did you set the business-onlinepayment configuration value?\n" + unless $processor; + + $payment_gateway = new FS::payment_gateway( { + gateway_namespace => $conf->config('business-onlinepayment-namespace'), + gateway_module => $processor, + gateway_username => $login, + gateway_password => $password, + gateway_action => $action, + options => [ ( @bop_options ) ], + }); + + } + + die "No real-time third party processor is enabled - ". + "did you set the business-onlinepayment configuration value?\n*" + unless $payment_gateway->gateway_namespace eq 'Business::OnlineThirdPartyPayment'; + + ### + # locate pending transaction + ### + + eval "use Business::OnlineThirdPartyPayment"; + die $@ if $@; + + my $transaction = + new Business::OnlineThirdPartyPayment( $payment_gateway->gateway_module, + @{ [ $payment_gateway->options ] }, + ); + + my $paypendingnum = $transaction->reference($packet->{data}); + + my $cust_pay_pending = + qsearchs('cust_pay_pending', { paypendingnum => $paypendingnum } ); + + unless ($cust_pay_pending) { + my $bill_error = "No payment is being processed with id $paypendingnum". + "; Transaction aborted."; + return { error => '_decline', bill_error => $bill_error }; + } + + if ($cust_pay_pending->status ne 'pending') { + my $bill_error = "Payment with id $paypendingnum is not pending, but ". + $cust_pay_pending->status. "; Transaction aborted."; + return { error => '_decline', bill_error => $bill_error }; + } + + my $cust_main = $cust_pay_pending->cust_main; + my $bill_error = + $cust_main->realtime_botpp_capture( $cust_pay_pending, %{$packet->{data}} ); + + return { 'error' => ( $bill_error->{bill_error} ? '_decline' : '' ), + %$bill_error, + }; + +} + 1; diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index b86930255..3921afdaa 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -8,6 +8,7 @@ use MIME::Base64; use FS::ConfItem; use FS::ConfDefaults; use FS::Conf_compat17; +use FS::payby; use FS::conf; use FS::Record qw(qsearch qsearchs); use FS::UID qw(dbh datasrc use_confcompat); @@ -619,6 +620,17 @@ worry that config_items is freeside-specific and icky. 'type' => 'textarea', }, + { + 'key' => 'business-onlinepayment-namespace', + 'section' => 'billing', + 'description' => 'Specifies which perl module namespace (which group of collection routines) is used by default.', + 'type' => 'select', + 'select_hash' => [ + 'Business::OnlinePayment' => 'Direct API (Business::OnlinePayment)', + 'Business::OnlineThirdPartyPayment' => 'Web API (Business::ThirdPartyPayment)', + ], + }, + { 'key' => 'business-onlinepayment-description', 'section' => 'billing', diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 885eaaa28..65f7a7f40 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -845,10 +845,12 @@ sub tables_hashref { 'payunique', 'varchar', 'NULL', $char_d, '', '', #separate paybatch "unique" functions from current usage 'status', 'varchar', '', $char_d, '', '', + 'session_id', 'varchar', 'NULL', $char_d, '', '', #only need 32 'statustext', 'text', 'NULL', '', '', '', 'gatewaynum', 'int', 'NULL', '', '', '', #'cust_balance', @money_type, '', '', 'paynum', 'int', 'NULL', '', '', '', + 'jobnum', 'int', 'NULL', '', '', '', ], 'primary_key' => 'paypendingnum', 'unique' => [ [ 'payunique' ] ], @@ -1857,10 +1859,12 @@ sub tables_hashref { 'payment_gateway' => { 'columns' => [ 'gatewaynum', 'serial', '', '', '', '', + 'gateway_namespace','varchar', 'NULL', $char_d, '', '', 'gateway_module', 'varchar', '', $char_d, '', '', 'gateway_username', 'varchar', 'NULL', $char_d, '', '', 'gateway_password', 'varchar', 'NULL', $char_d, '', '', 'gateway_action', 'varchar', 'NULL', $char_d, '', '', + 'gateway_callback_url', 'varchar', 'NULL', $char_d, '', '', 'disabled', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'gatewaynum', diff --git a/FS/FS/agent.pm b/FS/FS/agent.pm index ff0a2b1f6..e471e04a5 100644 --- a/FS/FS/agent.pm +++ b/FS/FS/agent.pm @@ -3,12 +3,14 @@ package FS::agent; use strict; use vars qw( @ISA ); #use Crypt::YAPassGen; +use Business::CreditCard 0.28; use FS::Record qw( dbh qsearch qsearchs ); use FS::cust_main; use FS::cust_pkg; use FS::agent_type; use FS::reg_code; use FS::TicketSystem; +use FS::Conf; @ISA = qw( FS::m2m_Common FS::Record ); @@ -200,6 +202,106 @@ sub ticketing_queue { FS::TicketSystem->queue($self->ticketing_queueid); }; +=item payment_gateway [ OPTION => VALUE, ... ] + +Returns a payment gateway object (see L) for this agent. + +Currently available options are I, I, and I. + +If I is set to the number of an invoice (see L) then +an attempt will be made to select a gateway suited for the taxes paid on +the invoice. + +The I and I options can be used to influence the choice +as well. Presently only 'CC' and 'ECHECK' methods are meaningful. + +When the I is 'CC' then the card number in I can direct +this routine to route to a gateway suited for that type of card. + +=cut + +sub payment_gateway { + my ( $self, %options ) = @_; + + my $taxclass = ''; + if ( $options{invnum} ) { + my $cust_bill = qsearchs('cust_bill', { 'invnum' => $options{invnum} } ); + die "invnum ". $options{'invnum'}. " not found" unless $cust_bill; + my @taxclasses = + map { $_->part_pkg->taxclass } + grep { $_ } + map { $_->cust_pkg } + $cust_bill->cust_bill_pkg; + unless ( grep { $taxclasses[0] ne $_ } @taxclasses ) { #unless there are + #different taxclasses $taxclass = $taxclasses[0]; + } + } + + #look for an agent gateway override first + my $cardtype; + if ( $options{method} && $options{method} eq 'CC' ) { + $cardtype = cardtype($options{payinfo}); + } elsif ( $options{method} && $options{method} eq 'ECHECK' ) { + $cardtype = 'ACH'; + } else { + $cardtype = $options{method} || ''; + } + + my $override = + qsearchs('agent_payment_gateway', { agentnum => $self->agentnum, + cardtype => $cardtype, + taxclass => $taxclass, } ) + || qsearchs('agent_payment_gateway', { agentnum => $self->agentnum, + cardtype => '', + taxclass => $taxclass, } ) + || qsearchs('agent_payment_gateway', { agentnum => $self->agentnum, + cardtype => $cardtype, + taxclass => '', } ) + || qsearchs('agent_payment_gateway', { agentnum => $self->agentnum, + cardtype => '', + taxclass => '', } ); + + my $payment_gateway = new FS::payment_gateway; + if ( $override ) { #use a payment gateway override + + $payment_gateway = $override->payment_gateway; + + } else { #use the standard settings from the config + # the standard settings from the config could be moved to a null agent + # agent_payment_gateway referenced payment_gateway + + my $conf = new FS::Conf; + die "Real-time processing not enabled\n" + unless $conf->exists('business-onlinepayment'); + + #load up config + my $bop_config = 'business-onlinepayment'; + $bop_config .= '-ach' + if ( $options{method} + && $options{method} =~ /^(ECHECK|CHEK)$/ + && $conf->exists($bop_config. '-ach') + ); + my ( $processor, $login, $password, $action, @bop_options ) = + $conf->config($bop_config); + $action ||= 'normal authorization'; + pop @bop_options if scalar(@bop_options) % 2 && $bop_options[-1] =~ /^\s*$/; + die "No real-time processor is enabled - ". + "did you set the business-onlinepayment configuration value?\n" + unless $processor; + + $payment_gateway->gateway_namespace( $conf->config('business-onlinepayment-namespace') || + 'Business::OnlinePayment'); + $payment_gateway->gateway_module($processor); + $payment_gateway->gateway_username($login); + $payment_gateway->gateway_password($password); + $payment_gateway->gateway_action($action); + $payment_gateway->set('options', [ @bop_options ]); + + } + + $payment_gateway; +} + =item num_prospect_cust_main Returns the number of prospects (customers with no packages ever ordered) for diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 865632f6c..2bad5ec3e 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3368,6 +3368,10 @@ sub retry_realtime { } +# some horrid false laziness here to avoid refactor fallout +# eventually realtime realtime_bop and realtime_refund_bop should go +# away and be replaced by _new_realtime_bop and _new_realtime_refund_bop + =item realtime_bop METHOD AMOUNT [ OPTION => VALUE ... ] Runs a realtime credit card, ACH (electronic check) or phone bill transaction @@ -3401,7 +3405,12 @@ I is a unique identifier for this payment. =cut sub realtime_bop { - my( $self, $method, $amount, %options ) = @_; + my $self = shift; + + return $self->_new_realtime_bop(@_) + if $self->_new_bop_required(); + + my( $method, $amount, %options ) = @_; if ( $DEBUG ) { warn "$me realtime_bop: $method $amount\n"; warn " $_ => $options{$_}\n" foreach keys %options; @@ -3942,119 +3951,6 @@ sub realtime_bop { } -=item fake_bop - -=cut - -sub fake_bop { - my( $self, $method, $amount, %options ) = @_; - - if ( $options{'fake_failure'} ) { - return "Error: No error; test failure requested with fake_failure"; - } - - my %method2payby = ( - 'CC' => 'CARD', - 'ECHECK' => 'CHEK', - 'LEC' => 'LECB', - ); - - #my $paybatch = ''; - #if ( $payment_gateway ) { # agent override - # $paybatch = $payment_gateway->gatewaynum. '-'; - #} - # - #$paybatch .= "$processor:". $transaction->authorization; - # - #$paybatch .= ':'. $transaction->order_number - # if $transaction->can('order_number') - # && length($transaction->order_number); - - my $paybatch = 'FakeProcessor:54:32'; - - my $cust_pay = new FS::cust_pay ( { - 'custnum' => $self->custnum, - 'invnum' => $options{'invnum'}, - 'paid' => $amount, - '_date' => '', - 'payby' => $method2payby{$method}, - #'payinfo' => $payinfo, - 'payinfo' => '4111111111111111', - 'paybatch' => $paybatch, - #'paydate' => $paydate, - 'paydate' => '2012-05-01', - } ); - $cust_pay->payunique( $options{payunique} ) if length($options{payunique}); - - my $error = $cust_pay->insert($options{'manual'} ? ( 'manual' => 1 ) : () ); - - if ( $error ) { - $cust_pay->invnum(''); #try again with no specific invnum - my $error2 = $cust_pay->insert( $options{'manual'} ? - ( 'manual' => 1 ) : () - ); - if ( $error2 ) { - # gah, even with transactions. - my $e = 'WARNING: Card/ACH debited but database not updated - '. - "error inserting (fake!) payment: $error2". - " (previously tried insert with invnum #$options{'invnum'}" . - ": $error )"; - warn $e; - return $e; - } - } - - if ( $options{'paynum_ref'} ) { - ${ $options{'paynum_ref'} } = $cust_pay->paynum; - } - - return ''; #no error - -} - -=item default_payment_gateway - -=cut - -sub default_payment_gateway { - my( $self, $method ) = @_; - - die "Real-time processing not enabled\n" - unless $conf->exists('business-onlinepayment'); - - #load up config - my $bop_config = 'business-onlinepayment'; - $bop_config .= '-ach' - if $method =~ /^(ECHECK|CHEK)$/ && $conf->exists($bop_config. '-ach'); - my ( $processor, $login, $password, $action, @bop_options ) = - $conf->config($bop_config); - $action ||= 'normal authorization'; - pop @bop_options if scalar(@bop_options) % 2 && $bop_options[-1] =~ /^\s*$/; - die "No real-time processor is enabled - ". - "did you set the business-onlinepayment configuration value?\n" - unless $processor; - - ( $processor, $login, $password, $action, @bop_options ) -} - -=item remove_cvv - -Removes the I field from the database directly. - -If there is an error, returns the error, otherwise returns false. - -=cut - -sub remove_cvv { - my $self = shift; - my $sth = dbh->prepare("UPDATE cust_main SET paycvv = '' WHERE custnum = ?") - or return dbh->errstr; - $sth->execute($self->custnum) - or return $sth->errstr; - $self->paycvv(''); - ''; -} - =item realtime_refund_bop METHOD [ OPTION => VALUE ... ] Refunds a realtime credit card, ACH (electronic check) or phone bill transaction @@ -4094,7 +3990,12 @@ gateway is attempted. #some false laziness w/realtime_bop, not enough to make it worth merging #but some useful small subs should be pulled out sub realtime_refund_bop { - my( $self, $method, %options ) = @_; + my $self = shift; + + return $self->_new_realtime_refund_bop(@_) + if $self->_new_bop_required(); + + my( $method, %options ) = @_; if ( $DEBUG ) { warn "$me realtime_refund_bop: $method refund\n"; warn " $_ => $options{$_}\n" foreach keys %options; @@ -4373,6 +4274,1285 @@ sub realtime_refund_bop { } +# does the configuration indicate the new bop routines are required? + +sub _new_bop_required { + my $self = shift; + + my $botpp = 'Business::OnlineThirdPartyPayment'; + + return 1 + if ( $conf->config('business-onlinepayment-namespace') eq $botpp || + scalar( grep { $_->gateway_namespace eq $botpp } + qsearch( 'payment_gateway', { 'disabled' => '' } ) + ) + ) + ; + + ''; +} + + +=item realtime_collect [ OPTION => VALUE ... ] + +Runs a realtime credit card, ACH (electronic check) or phone bill transaction +via a Business::OnlinePayment or Business::OnlineThirdPartyPayment realtime +gateway. See L and +L for supported gateways. + +On failure returns an error message. + +Returns false or a hashref upon success. The hashref contains keys popup_url reference, and collectitems. The first is a URL to which a browser should be redirected for completion of collection. The second is a reference id for the transaction suitable for the end user. The collectitems is a reference to a list of name value pairs suitable for assigning to a html form and posted to popup_url. + +Available options are: I, I, I, I, I, I, I, I + +I is one of: I, I and I. If none is specified +then it is deduced from the customer record. + +If no I is specified, then the customer balance is used. + +The additional options I, I, I, I, I, +I, I and I are also available. Any of these options, +if set, will override the value from the customer record. + +I is a free-text field passed to the gateway. It defaults to +"Internet services". + +If an I is specified, this payment (if successful) is applied to the +specified invoice. If you don't specify an I you might want to +call the B method. + +I can be set true to surpress email decline notices. + +I can be set to a scalar reference. It will be filled in with the +resulting paynum, if any. + +I is a unique identifier for this payment. + +I is a session identifier associated with this payment. + +I allows payment capture to unlock export jobs + +=cut + +sub realtime_collect { + my( $self, %options ) = @_; + + if ( $DEBUG ) { + warn "$me realtime_collect:\n"; + warn " $_ => $options{$_}\n" foreach keys %options; + } + + $options{amount} = $self->balance unless exists( $options{amount} ); + $options{method} = FS::payby->payby2bop($self->payby) + unless exists( $options{method} ); + + return $self->realtime_bop({%options}); + +} + +=item _realtime_bop { [ ARG => VALUE ... ] } + +Runs a realtime credit card, ACH (electronic check) or phone bill transaction +via a Business::OnlinePayment realtime gateway. See +L for supported gateways. + +Required arguments in the hashref are I, and I + +Available methods are: I, I and I + +Available optional arguments are: I, I, I, I, I, I + +The additional options I, I, I, I, I, +I, I and I are also available. Any of these options, +if set, will override the value from the customer record. + +I is a free-text field passed to the gateway. It defaults to +"Internet services". + +If an I is specified, this payment (if successful) is applied to the +specified invoice. If you don't specify an I you might want to +call the B method. + +I can be set true to surpress email decline notices. + +I can be set to a scalar reference. It will be filled in with the +resulting paynum, if any. + +I is a unique identifier for this payment. + +I is a session identifier associated with this payment. + +I allows payment capture to unlock export jobs + +(moved from cust_bill) (probably should get realtime_{card,ach,lec} here too) + +=cut + +# some helper routines +sub _payment_gateway { + my ($self, $options) = @_; + + $options->{payment_gateway} = $self->agent->payment_gateway( %$options ) + unless exists($options->{payment_gateway}); + + $options->{payment_gateway}; +} + +sub _bop_auth { + my ($self, $options) = @_; + + ( + 'login' => $options->{payment_gateway}->gateway_username, + 'password' => $options->{payment_gateway}->gateway_password, + ); +} + +sub _bop_options { + my ($self, $options) = @_; + + $options->{payment_gateway}->gatewaynum + ? $options->{payment_gateway}->options + : @{ $options->{payment_gateway}->get('options') }; +} + +sub _bop_defaults { + my ($self, $options) = @_; + + $options->{description} ||= 'Internet services'; + $options->{payinfo} = $self->payinfo unless exists( $options->{payinfo} ); + $options->{invnum} ||= ''; + $options->{payname} = $self->payname unless exists( $options->{payname} ); +} + +sub _bop_content { + my ($self, $options) = @_; + my %content = (); + + $content{address} = exists($options->{'address1'}) + ? $options->{'address1'} + : $self->address1; + my $address2 = exists($options->{'address2'}) + ? $options->{'address2'} + : $self->address2; + $content{address} .= ", ". $address2 if length($address2); + + my $payip = exists($options->{'payip'}) ? $options->{'payip'} : $self->payip; + $content{customer_ip} = $payip if length($payip); + + $content{invoice_number} = $options->{'invnum'} + if exists($options->{'invnum'}) && length($options->{'invnum'}); + + $content{email_customer} = + ( $conf->exists('business-onlinepayment-email_customer') + || $conf->exists('business-onlinepayment-email-override') ); + + $content{payfirst} = $self->getfield('first'); + $content{paylast} = $self->getfield('last'); + + $content{account_name} = "$content{payfirst} $content{paylast}" + if $options->{method} eq 'ECHECK'; + + $content{name} = $options->{payname}; + $content{name} = $content{account_name} if exists($content{account_name}); + + $content{city} = exists($options->{city}) + ? $options->{city} + : $self->city; + $content{state} = exists($options->{state}) + ? $options->{state} + : $self->state; + $content{zip} = exists($options->{zip}) + ? $options->{'zip'} + : $self->zip; + $content{country} = exists($options->{country}) + ? $options->{country} + : $self->country; + $content{referer} = 'http://cleanwhisker.420.am/'; #XXX fix referer :/ + $content{phone} = $self->daytime || $self->night; + + (%content); +} + +my %bop_method2payby = ( + 'CC' => 'CARD', + 'ECHECK' => 'CHEK', + 'LEC' => 'LECB', +); + +sub _new_realtime_bop { + my $self = shift; + + my %options = (); + if (ref($_[0]) eq 'HASH') { + %options = %{$_[0]}; + } else { + my ( $method, $amount ) = ( shift, shift ); + %options = @_; + $options{method} = $method; + $options{amount} = $amount; + } + + if ( $DEBUG ) { + warn "$me realtime_bop (new): $options{method} $options{amount}\n"; + warn " $_ => $options{$_}\n" foreach keys %options; + } + + return $self->fake_bop(%options) if $options{'fake'}; + + $self->_bop_defaults(\%options); + + ### + # select a gateway + ### + + my $payment_gateway = $self->_payment_gateway( \%options ); + my $namespace = $payment_gateway->gateway_namespace; + + eval "use $namespace"; + die $@ if $@; + + ### + # check for banned credit card/ACH + ### + + my $ban = qsearchs('banned_pay', { + 'payby' => $bop_method2payby{$options{method}}, + 'payinfo' => md5_base64($options{payinfo}), + } ); + return "Banned credit card" if $ban; + + ### + # massage data + ### + + my (%bop_content) = $self->_bop_content(\%options); + + if ( $options{method} ne 'ECHECK' ) { + $options{payname} =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/ + or return "Illegal payname $options{payname}"; + ($bop_content{payfirst}, $bop_content{paylast}) = ($1, $2); + } + + my @invoicing_list = $self->invoicing_list_emailonly; + if ( $conf->exists('emailinvoiceautoalways') + || $conf->exists('emailinvoiceauto') && ! @invoicing_list + || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) { + push @invoicing_list, $self->all_emails; + } + + my $email = ($conf->exists('business-onlinepayment-email-override')) + ? $conf->config('business-onlinepayment-email-override') + : $invoicing_list[0]; + + my $paydate = ''; + my %content = (); + if ( $namespace eq 'Business::OnlinePayment' && $options{method} eq 'CC' ) { + + $content{card_number} = $options{payinfo}; + $paydate = exists($options{'paydate'}) + ? $options{'paydate'} + : $self->paydate; + $paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; + $content{expiration} = "$2/$1"; + + my $paycvv = exists($options{'paycvv'}) + ? $options{'paycvv'} + : $self->paycvv; + $content{cvv2} = $paycvv + if length($paycvv); + + my $paystart_month = exists($options{'paystart_month'}) + ? $options{'paystart_month'} + : $self->paystart_month; + + my $paystart_year = exists($options{'paystart_year'}) + ? $options{'paystart_year'} + : $self->paystart_year; + + $content{card_start} = "$paystart_month/$paystart_year" + if $paystart_month && $paystart_year; + + my $payissue = exists($options{'payissue'}) + ? $options{'payissue'} + : $self->payissue; + $content{issue_number} = $payissue if $payissue; + + $content{recurring_billing} = 'YES' + if qsearch('cust_pay', { 'custnum' => $self->custnum, + 'payby' => 'CARD', + 'payinfo' => $options{payinfo}, + } ) + || qsearch('cust_pay', { 'custnum' => $self->custnum, + 'payby' => 'CARD', + 'paymask' => $self->mask_payinfo('CARD', $options{payinfo}), + } ); + + + } elsif ( $namespace eq 'Business::OnlinePayment' && $options{method} eq 'ECHECK' ){ + ( $content{account_number}, $content{routing_code} ) = + split('@', $options{payinfo}); + $content{bank_name} = $options{payname}; + $content{bank_state} = exists($options{'paystate'}) + ? $options{'paystate'} + : $self->getfield('paystate'); + $content{account_type} = exists($options{'paytype'}) + ? uc($options{'paytype'}) || 'CHECKING' + : uc($self->getfield('paytype')) || 'CHECKING'; + $content{customer_org} = $self->company ? 'B' : 'I'; + $content{state_id} = exists($options{'stateid'}) + ? $options{'stateid'} + : $self->getfield('stateid'); + $content{state_id_state} = exists($options{'stateid_state'}) + ? $options{'stateid_state'} + : $self->getfield('stateid_state'); + $content{customer_ssn} = exists($options{'ss'}) + ? $options{'ss'} + : $self->ss; + } elsif ( $namespace eq 'Business::OnlinePayment' && $options{method} eq 'LEC' ) { + $content{phone} = $options{payinfo}; + } elsif ( $namespace eq 'Business::OnlineThirdPartyPayment' ) { + #move along + } else { + #die an evil death + } + + ### + # run transaction(s) + ### + + my $balance = exists( $options{'balance'} ) + ? $options{'balance'} + : $self->balance; + + $self->select_for_update; #mutex ... just until we get our pending record in + + #the checks here are intended to catch concurrent payments + #double-form-submission prevention is taken care of in cust_pay_pending::check + + #check the balance + return "The customer's balance has changed; $options{method} transaction aborted." + if $self->balance < $balance; + #&& $self->balance < $options{amount}; #might as well anyway? + + #also check and make sure there aren't *other* pending payments for this cust + + my @pending = qsearch('cust_pay_pending', { + 'custnum' => $self->custnum, + 'status' => { op=>'!=', value=>'done' } + }); + return "A payment is already being processed for this customer (". + join(', ', map 'paypendingnum '. $_->paypendingnum, @pending ). + "); $options{method} transaction aborted." + if scalar(@pending); + + #okay, good to go, if we're a duplicate, cust_pay_pending will kick us out + + my $cust_pay_pending = new FS::cust_pay_pending { + 'custnum' => $self->custnum, + #'invnum' => $options{'invnum'}, + 'paid' => $options{amount}, + '_date' => '', + 'payby' => $bop_method2payby{$options{method}}, + 'payinfo' => $options{payinfo}, + 'paydate' => $paydate, + 'status' => 'new', + 'gatewaynum' => $payment_gateway->gatewaynum || '', + 'session_id' => $options{session_id} || '', + 'jobnum' => $options{depend_jobnum} || '', + }; + $cust_pay_pending->payunique( $options{payunique} ) + if defined($options{payunique}) && length($options{payunique}); + my $cpp_new_err = $cust_pay_pending->insert; #mutex lost when this is inserted + return $cpp_new_err if $cpp_new_err; + + my( $action1, $action2 ) = + split( /\s*\,\s*/, $payment_gateway->gateway_action ); + + my $transaction = new $namespace( $payment_gateway->gateway_module, + $self->_bop_options(\%options), + ); + + $transaction->content( + 'type' => $options{method}, + $self->_bop_auth(\%options), + 'action' => $action1, + 'description' => $options{'description'}, + 'amount' => $options{amount}, + #'invoice_number' => $options{'invnum'}, + 'customer_id' => $self->custnum, + %bop_content, + 'reference' => $cust_pay_pending->paypendingnum, #for now + 'email' => $email, + %content, #after + ); + + $cust_pay_pending->status('pending'); + my $cpp_pending_err = $cust_pay_pending->replace; + return $cpp_pending_err if $cpp_pending_err; + + #config? + my $BOP_TESTING = 0; + my $BOP_TESTING_SUCCESS = 1; + + unless ( $BOP_TESTING ) { + $transaction->submit(); + } else { + if ( $BOP_TESTING_SUCCESS ) { + $transaction->is_success(1); + $transaction->authorization('fake auth'); + } else { + $transaction->is_success(0); + $transaction->error_message('fake failure'); + } + } + + if ( $transaction->is_success() && $namespace eq 'Business::OnlineThirdPartyPayment' ) { + + return { reference => $cust_pay_pending->paypendingnum, + map { $_ => $transaction->$_ } qw ( popup_url collectitems ) }; + + } elsif ( $transaction->is_success() && $action2 ) { + + $cust_pay_pending->status('authorized'); + my $cpp_authorized_err = $cust_pay_pending->replace; + return $cpp_authorized_err if $cpp_authorized_err; + + my $auth = $transaction->authorization; + my $ordernum = $transaction->can('order_number') + ? $transaction->order_number + : ''; + + my $capture = + new Business::OnlinePayment( $payment_gateway->gateway_module, + $self->_bop_options(\%options), + ); + + my %capture = ( + %content, + type => $options{method}, + action => $action2, + $self->_bop_auth(\%options), + order_number => $ordernum, + amount => $options{amount}, + authorization => $auth, + description => $options{'description'}, + ); + + foreach my $field (qw( authorization_source_code returned_ACI + transaction_identifier validation_code + transaction_sequence_num local_transaction_date + local_transaction_time AVS_result_code )) { + $capture{$field} = $transaction->$field() if $transaction->can($field); + } + + $capture->content( %capture ); + + $capture->submit(); + + unless ( $capture->is_success ) { + my $e = "Authorization successful but capture failed, custnum #". + $self->custnum. ': '. $capture->result_code. + ": ". $capture->error_message; + warn $e; + return $e; + } + + } + + ### + # remove paycvv after initial transaction + ### + + #false laziness w/misc/process/payment.cgi - check both to make sure working + # correctly + if ( defined $self->dbdef_table->column('paycvv') + && length($self->paycvv) + && ! grep { $_ eq cardtype($options{payinfo}) } $conf->config('cvv-save') + ) { + my $error = $self->remove_cvv; + if ( $error ) { + warn "WARNING: error removing cvv: $error\n"; + } + } + + ### + # result handling + ### + + $self->_realtime_bop_result( $cust_pay_pending, $transaction, %options ); + +} + +=item fake_bop + +=cut + +sub fake_bop { + my $self = shift; + + my %options = (); + if (ref($_[0]) eq 'HASH') { + %options = %{$_[0]}; + } else { + my ( $method, $amount ) = ( shift, shift ); + %options = @_; + $options{method} = $method; + $options{amount} = $amount; + } + + if ( $options{'fake_failure'} ) { + return "Error: No error; test failure requested with fake_failure"; + } + + #my $paybatch = ''; + #if ( $payment_gateway->gatewaynum ) { # agent override + # $paybatch = $payment_gateway->gatewaynum. '-'; + #} + # + #$paybatch .= "$processor:". $transaction->authorization; + # + #$paybatch .= ':'. $transaction->order_number + # if $transaction->can('order_number') + # && length($transaction->order_number); + + my $paybatch = 'FakeProcessor:54:32'; + + my $cust_pay = new FS::cust_pay ( { + 'custnum' => $self->custnum, + 'invnum' => $options{'invnum'}, + 'paid' => $options{amount}, + '_date' => '', + 'payby' => $bop_method2payby{$options{method}}, + #'payinfo' => $payinfo, + 'payinfo' => '4111111111111111', + 'paybatch' => $paybatch, + #'paydate' => $paydate, + 'paydate' => '2012-05-01', + } ); + $cust_pay->payunique( $options{payunique} ) if length($options{payunique}); + + my $error = $cust_pay->insert($options{'manual'} ? ( 'manual' => 1 ) : () ); + + if ( $error ) { + $cust_pay->invnum(''); #try again with no specific invnum + my $error2 = $cust_pay->insert( $options{'manual'} ? + ( 'manual' => 1 ) : () + ); + if ( $error2 ) { + # gah, even with transactions. + my $e = 'WARNING: Card/ACH debited but database not updated - '. + "error inserting (fake!) payment: $error2". + " (previously tried insert with invnum #$options{'invnum'}" . + ": $error )"; + warn $e; + return $e; + } + } + + if ( $options{'paynum_ref'} ) { + ${ $options{'paynum_ref'} } = $cust_pay->paynum; + } + + return ''; #no error + +} + + +# item _realtime_bop_result CUST_PAY_PENDING, BOP_OBJECT [ OPTION => VALUE ... ] +# +# Wraps up processing of a realtime credit card, ACH (electronic check) or +# phone bill transaction. + +sub _realtime_bop_result { + my( $self, $cust_pay_pending, $transaction, %options ) = @_; + if ( $DEBUG ) { + warn "$me _realtime_bop_result: pending transaction ". + $cust_pay_pending->paypendingnum. "\n"; + warn " $_ => $options{$_}\n" foreach keys %options; + } + + my $payment_gateway = $options{payment_gateway} + or return "no payment gateway in arguments to _realtime_bop_result"; + + $cust_pay_pending->status($transaction->is_success() ? 'captured' : 'declined'); + my $cpp_captured_err = $cust_pay_pending->replace; + return $cpp_captured_err if $cpp_captured_err; + + if ( $transaction->is_success() ) { + + my $paybatch = ''; + if ( $payment_gateway->gatewaynum ) { # agent override + $paybatch = $payment_gateway->gatewaynum. '-'; + } + + $paybatch .= $payment_gateway->gateway_module. ":". + $transaction->authorization; + + $paybatch .= ':'. $transaction->order_number + if $transaction->can('order_number') + && length($transaction->order_number); + + my $cust_pay = new FS::cust_pay ( { + 'custnum' => $self->custnum, + 'invnum' => $options{'invnum'}, + 'paid' => $cust_pay_pending->paid, + '_date' => '', + 'payby' => $cust_pay_pending->payby, + #'payinfo' => $payinfo, + 'paybatch' => $paybatch, + 'paydate' => $cust_pay_pending->paydate, + } ); + #doesn't hurt to know, even though the dup check is in cust_pay_pending now + $cust_pay->payunique( $options{payunique} ) + if defined($options{payunique}) && length($options{payunique}); + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + #start a transaction, insert the cust_pay and set cust_pay_pending.status to done in a single transction + + my $error = $cust_pay->insert($options{'manual'} ? ( 'manual' => 1 ) : () ); + + if ( $error ) { + $cust_pay->invnum(''); #try again with no specific invnum + my $error2 = $cust_pay->insert( $options{'manual'} ? + ( 'manual' => 1 ) : () + ); + if ( $error2 ) { + # gah. but at least we have a record of the state we had to abort in + # from cust_pay_pending now. + my $e = "WARNING: $options{method} captured but payment not recorded -". + " error inserting payment (". $payment_gateway->gateway_module. + "): $error2". + " (previously tried insert with invnum #$options{'invnum'}" . + ": $error ) - pending payment saved as paypendingnum ". + $cust_pay_pending->paypendingnum. "\n"; + warn $e; + return $e; + } + } + + my $jobnum = $cust_pay_pending->jobnum; + if ( $jobnum ) { + my $placeholder = qsearchs( 'queue', { 'jobnum' => $jobnum } ); + + unless ( $placeholder ) { + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + my $e = "WARNING: $options{method} captured but job $jobnum not ". + "found for paypendingnum ". $cust_pay_pending->paypendingnum. "\n"; + warn $e; + return $e; + } + + $error = $placeholder->delete; + + if ( $error ) { + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + my $e = "WARNING: $options{method} captured but could not delete ". + "job $jobnum for paypendingnum ". + $cust_pay_pending->paypendingnum. ": $error\n"; + warn $e; + return $e; + } + + } + + if ( $options{'paynum_ref'} ) { + ${ $options{'paynum_ref'} } = $cust_pay->paynum; + } + + $cust_pay_pending->status('done'); + $cust_pay_pending->statustext('captured'); + $cust_pay_pending->paynum($cust_pay->paynum); + my $cpp_done_err = $cust_pay_pending->replace; + + if ( $cpp_done_err ) { + + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; + my $e = "WARNING: $options{method} captured but payment not recorded - ". + "error updating status for paypendingnum ". + $cust_pay_pending->paypendingnum. ": $cpp_done_err \n"; + warn $e; + return $e; + + } else { + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return ''; #no error + + } + + } else { + + my $perror = $payment_gateway->gateway_module. " error: ". + $transaction->error_message; + + my $jobnum = $cust_pay_pending->jobnum; + if ( $jobnum ) { + my $placeholder = qsearchs( 'queue', { 'jobnum' => $jobnum } ); + + if ( $placeholder ) { + my $error = $placeholder->depended_delete; + $error ||= $placeholder->delete; + warn "error removing provisioning jobs after declined paypendingnum ". + $cust_pay_pending->paypendingnum. "\n"; + } else { + my $e = "error finding job $jobnum for declined paypendingnum ". + $cust_pay_pending->paypendingnum. "\n"; + warn $e; + } + + } + + unless ( $transaction->error_message ) { + + my $t_response; + if ( $transaction->can('response_page') ) { + $t_response = { + 'page' => ( $transaction->can('response_page') + ? $transaction->response_page + : '' + ), + 'code' => ( $transaction->can('response_code') + ? $transaction->response_code + : '' + ), + 'headers' => ( $transaction->can('response_headers') + ? $transaction->response_headers + : '' + ), + }; + } else { + $t_response .= + "No additional debugging information available for ". + $payment_gateway->gateway_module; + } + + $perror .= "No error_message returned from ". + $payment_gateway->gateway_module. " -- ". + ( ref($t_response) ? Dumper($t_response) : $t_response ); + + } + + if ( !$options{'quiet'} && !$realtime_bop_decline_quiet + && $conf->exists('emaildecline') + && grep { $_ ne 'POST' } $self->invoicing_list + && ! grep { $transaction->error_message =~ /$_/ } + $conf->config('emaildecline-exclude') + ) { + my @templ = $conf->config('declinetemplate'); + my $template = new Text::Template ( + TYPE => 'ARRAY', + SOURCE => [ map "$_\n", @templ ], + ) or return "($perror) can't create template: $Text::Template::ERROR"; + $template->compile() + or return "($perror) can't compile template: $Text::Template::ERROR"; + + my $templ_hash = { error => $transaction->error_message }; + + my $error = send_email( + 'from' => $conf->config('invoice_from', $self->agentnum ), + 'to' => [ grep { $_ ne 'POST' } $self->invoicing_list ], + 'subject' => 'Your payment could not be processed', + 'body' => [ $template->fill_in(HASH => $templ_hash) ], + ); + + $perror .= " (also received error sending decline notification: $error)" + if $error; + + } + + $cust_pay_pending->status('done'); + $cust_pay_pending->statustext("declined: $perror"); + my $cpp_done_err = $cust_pay_pending->replace; + if ( $cpp_done_err ) { + my $e = "WARNING: $options{method} declined but pending payment not ". + "resolved - error updating status for paypendingnum ". + $cust_pay_pending->paypendingnum. ": $cpp_done_err \n"; + warn $e; + $perror = "$e ($perror)"; + } + + return $perror; + } + +} + +=item realtime_botpp_capture CUST_PAY_PENDING [ OPTION => VALUE ... ] + +Verifies successful third party processing of a realtime credit card, +ACH (electronic check) or phone bill transaction via a +Business::OnlineThirdPartyPayment realtime gateway. See +L for supported gateways. + +Available options are: I, I, I, I, I + +The additional options I, I, I, +I, I and I are also available. Any of these options, +if set, will override the value from the customer record. + +I is a free-text field passed to the gateway. It defaults to +"Internet services". + +If an I is specified, this payment (if successful) is applied to the +specified invoice. If you don't specify an I you might want to +call the B method. + +I can be set true to surpress email decline notices. + +I can be set to a scalar reference. It will be filled in with the +resulting paynum, if any. + +I is a unique identifier for this payment. + +Returns a hashref containing elements bill_error (which will be undefined +upon success) and session_id of any associated session. + +=cut + +sub realtime_botpp_capture { + my( $self, $cust_pay_pending, %options ) = @_; + if ( $DEBUG ) { + warn "$me realtime_botpp_capture: pending transaction $cust_pay_pending\n"; + warn " $_ => $options{$_}\n" foreach keys %options; + } + + eval "use Business::OnlineThirdPartyPayment"; + die $@ if $@; + + ### + # select the gateway + ### + + my $method = FS::payby->payby2bop($cust_pay_pending->payby); + + my $payment_gateway = $cust_pay_pending->gatewaynum + ? qsearchs( 'payment_gateway', + { gatewaynum => $cust_pay_pending->gatewaynum } + ) + : $self->agent->payment_gateway( 'method' => $method, + # 'invnum' => $cust_pay_pending->invnum, + # 'payinfo' => $cust_pay_pending->payinfo, + ); + + $options{payment_gateway} = $payment_gateway; # for the helper subs + + ### + # massage data + ### + + my @invoicing_list = $self->invoicing_list_emailonly; + if ( $conf->exists('emailinvoiceautoalways') + || $conf->exists('emailinvoiceauto') && ! @invoicing_list + || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) { + push @invoicing_list, $self->all_emails; + } + + my $email = ($conf->exists('business-onlinepayment-email-override')) + ? $conf->config('business-onlinepayment-email-override') + : $invoicing_list[0]; + + my %content = (); + + $content{email_customer} = + ( $conf->exists('business-onlinepayment-email_customer') + || $conf->exists('business-onlinepayment-email-override') ); + + ### + # run transaction(s) + ### + + my $transaction = + new Business::OnlineThirdPartyPayment( $payment_gateway->gateway_module, + $self->_bop_options(\%options), + ); + + $transaction->reference({ %options }); + + $transaction->content( + 'type' => $method, + $self->_bop_auth(\%options), + 'action' => 'Post Authorization', + 'description' => $options{'description'}, + 'amount' => $cust_pay_pending->paid, + #'invoice_number' => $options{'invnum'}, + 'customer_id' => $self->custnum, + 'referer' => 'http://cleanwhisker.420.am/', + 'reference' => $cust_pay_pending->paypendingnum, + 'email' => $email, + 'phone' => $self->daytime || $self->night, + %content, #after + # plus whatever is required for bogus capture avoidance + ); + + $transaction->submit(); + + my $error = + $self->_realtime_bop_result( $cust_pay_pending, $transaction, %options ); + + { + bill_error => $error, + session_id => $cust_pay_pending->session_id, + } + +} + +=item default_payment_gateway DEPRECATED -- use agent->payment_gateway + +=cut + +sub default_payment_gateway { + my( $self, $method ) = @_; + + die "Real-time processing not enabled\n" + unless $conf->exists('business-onlinepayment'); + + #warn "default_payment_gateway deprecated -- use agent->payment_gateway\n"; + + #load up config + my $bop_config = 'business-onlinepayment'; + $bop_config .= '-ach' + if $method =~ /^(ECHECK|CHEK)$/ && $conf->exists($bop_config. '-ach'); + my ( $processor, $login, $password, $action, @bop_options ) = + $conf->config($bop_config); + $action ||= 'normal authorization'; + pop @bop_options if scalar(@bop_options) % 2 && $bop_options[-1] =~ /^\s*$/; + die "No real-time processor is enabled - ". + "did you set the business-onlinepayment configuration value?\n" + unless $processor; + + ( $processor, $login, $password, $action, @bop_options ) +} + +=item remove_cvv + +Removes the I field from the database directly. + +If there is an error, returns the error, otherwise returns false. + +=cut + +sub remove_cvv { + my $self = shift; + my $sth = dbh->prepare("UPDATE cust_main SET paycvv = '' WHERE custnum = ?") + or return dbh->errstr; + $sth->execute($self->custnum) + or return $sth->errstr; + $self->paycvv(''); + ''; +} + +=item _new_realtime_refund_bop METHOD [ OPTION => VALUE ... ] + +Refunds a realtime credit card, ACH (electronic check) or phone bill transaction +via a Business::OnlinePayment realtime gateway. See +L for supported gateways. + +Available methods are: I, I and I + +Available options are: I, I, I, I + +Most gateways require a reference to an original payment transaction to refund, +so you probably need to specify a I. + +I defaults to the original amount of the payment if not specified. + +I specifies a reason for the refund. + +I specifies the expiration date for a credit card overriding the +value from the customer record or the payment record. Specified as yyyy-mm-dd + +Implementation note: If I is unspecified or equal to the amount of the +orignal payment, first an attempt is made to "void" the transaction via +the gateway (to cancel a not-yet settled transaction) and then if that fails, +the normal attempt is made to "refund" ("credit") the transaction via the +gateway is attempted. + +#The additional options I, I, I, I, I, +#I, I and I are also available. Any of these options, +#if set, will override the value from the customer record. + +#If an I is specified, this payment (if successful) is applied to the +#specified invoice. If you don't specify an I you might want to +#call the B method. + +=cut + +#some false laziness w/realtime_bop, not enough to make it worth merging +#but some useful small subs should be pulled out +sub _new_realtime_refund_bop { + my $self = shift; + + my %options = (); + if (ref($_[0]) ne 'HASH') { + %options = %{$_[0]}; + } else { + my $method = shift; + %options = @_; + $options{method} = $method; + } + + if ( $DEBUG ) { + warn "$me realtime_refund_bop (new): $options{method} refund\n"; + warn " $_ => $options{$_}\n" foreach keys %options; + } + + ### + # look up the original payment and optionally a gateway for that payment + ### + + my $cust_pay = ''; + my $amount = $options{'amount'}; + + my( $processor, $login, $password, @bop_options, $namespace ) ; + my( $auth, $order_number ) = ( '', '', '' ); + + if ( $options{'paynum'} ) { + + warn " paynum: $options{paynum}\n" if $DEBUG > 1; + $cust_pay = qsearchs('cust_pay', { paynum=>$options{'paynum'} } ) + or return "Unknown paynum $options{'paynum'}"; + $amount ||= $cust_pay->paid; + + $cust_pay->paybatch =~ /^((\d+)\-)?(\w+):\s*([\w\-\/ ]*)(:([\w\-]+))?$/ + or return "Can't parse paybatch for paynum $options{'paynum'}: ". + $cust_pay->paybatch; + my $gatewaynum = ''; + ( $gatewaynum, $processor, $auth, $order_number ) = ( $2, $3, $4, $6 ); + + if ( $gatewaynum ) { #gateway for the payment to be refunded + + my $payment_gateway = + qsearchs('payment_gateway', { 'gatewaynum' => $gatewaynum } ); + die "payment gateway $gatewaynum not found" + unless $payment_gateway; + + $processor = $payment_gateway->gateway_module; + $login = $payment_gateway->gateway_username; + $password = $payment_gateway->gateway_password; + $namespace = $payment_gateway->gateway_namespace; + @bop_options = $payment_gateway->options; + + } else { #try the default gateway + + my $conf_processor; + my $payment_gateway = + $self->agent->payment_gateway('method' => $options{method}); + + ( $conf_processor, $login, $password, $namespace ) = + map { my $method = "gateway_$_"; $payment_gateway->$method } + qw( module username password namespace ); + + @bop_options = $payment_gateway->gatewaynum + ? $payment_gateway->options + : @{ $payment_gateway->get('options') }; + + return "processor of payment $options{'paynum'} $processor does not". + " match default processor $conf_processor" + unless $processor eq $conf_processor; + + } + + + } else { # didn't specify a paynum, so look for agent gateway overrides + # like a normal transaction + + my $payment_gateway = + $self->agent->payment_gateway( 'method' => $options{method}, + #'payinfo' => $payinfo, + ); + my( $processor, $login, $password, $namespace ) = + map { my $method = "gateway_$_"; $payment_gateway->$method } + qw( module username password namespace ); + + my @bop_options = $payment_gateway->gatewaynum + ? $payment_gateway->options + : @{ $payment_gateway->get('options') }; + + } + return "neither amount nor paynum specified" unless $amount; + + eval "use $namespace"; + die $@ if $@; + + my %content = ( + 'type' => $options{method}, + 'login' => $login, + 'password' => $password, + 'order_number' => $order_number, + 'amount' => $amount, + 'referer' => 'http://cleanwhisker.420.am/', #XXX fix referer :/ + ); + $content{authorization} = $auth + if length($auth); #echeck/ACH transactions have an order # but no auth + #(at least with authorize.net) + + my $disable_void_after; + if ($conf->exists('disable_void_after') + && $conf->config('disable_void_after') =~ /^(\d+)$/) { + $disable_void_after = $1; + } + + #first try void if applicable + if ( $cust_pay && $cust_pay->paid == $amount + && ( + ( not defined($disable_void_after) ) + || ( time < ($cust_pay->_date + $disable_void_after ) ) + ) + ) { + warn " attempting void\n" if $DEBUG > 1; + my $void = new Business::OnlinePayment( $processor, @bop_options ); + $void->content( 'action' => 'void', %content ); + $void->submit(); + if ( $void->is_success ) { + my $error = $cust_pay->void($options{'reason'}); + if ( $error ) { + # gah, even with transactions. + my $e = 'WARNING: Card/ACH voided but database not updated - '. + "error voiding payment: $error"; + warn $e; + return $e; + } + warn " void successful\n" if $DEBUG > 1; + return ''; + } + } + + warn " void unsuccessful, trying refund\n" + if $DEBUG > 1; + + #massage data + my $address = $self->address1; + $address .= ", ". $self->address2 if $self->address2; + + my($payname, $payfirst, $paylast); + if ( $self->payname && $options{method} ne 'ECHECK' ) { + $payname = $self->payname; + $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/ + or return "Illegal payname $payname"; + ($payfirst, $paylast) = ($1, $2); + } else { + $payfirst = $self->getfield('first'); + $paylast = $self->getfield('last'); + $payname = "$payfirst $paylast"; + } + + my @invoicing_list = $self->invoicing_list_emailonly; + if ( $conf->exists('emailinvoiceautoalways') + || $conf->exists('emailinvoiceauto') && ! @invoicing_list + || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) { + push @invoicing_list, $self->all_emails; + } + + my $email = ($conf->exists('business-onlinepayment-email-override')) + ? $conf->config('business-onlinepayment-email-override') + : $invoicing_list[0]; + + my $payip = exists($options{'payip'}) + ? $options{'payip'} + : $self->payip; + $content{customer_ip} = $payip + if length($payip); + + my $payinfo = ''; + if ( $options{method} eq 'CC' ) { + + if ( $cust_pay ) { + $content{card_number} = $payinfo = $cust_pay->payinfo; + (exists($options{'paydate'}) ? $options{'paydate'} : $cust_pay->paydate) + =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/ && + ($content{expiration} = "$2/$1"); # where available + } else { + $content{card_number} = $payinfo = $self->payinfo; + (exists($options{'paydate'}) ? $options{'paydate'} : $self->paydate) + =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; + $content{expiration} = "$2/$1"; + } + + } elsif ( $options{method} eq 'ECHECK' ) { + + if ( $cust_pay ) { + $payinfo = $cust_pay->payinfo; + } else { + $payinfo = $self->payinfo; + } + ( $content{account_number}, $content{routing_code} )= split('@', $payinfo ); + $content{bank_name} = $self->payname; + $content{account_type} = 'CHECKING'; + $content{account_name} = $payname; + $content{customer_org} = $self->company ? 'B' : 'I'; + $content{customer_ssn} = $self->ss; + } elsif ( $options{method} eq 'LEC' ) { + $content{phone} = $payinfo = $self->payinfo; + } + + #then try refund + my $refund = new Business::OnlinePayment( $processor, @bop_options ); + my %sub_content = $refund->content( + 'action' => 'credit', + 'customer_id' => $self->custnum, + 'last_name' => $paylast, + 'first_name' => $payfirst, + 'name' => $payname, + 'address' => $address, + 'city' => $self->city, + 'state' => $self->state, + 'zip' => $self->zip, + 'country' => $self->country, + 'email' => $email, + 'phone' => $self->daytime || $self->night, + %content, #after + ); + warn join('', map { " $_ => $sub_content{$_}\n" } keys %sub_content ) + if $DEBUG > 1; + $refund->submit(); + + return "$processor error: ". $refund->error_message + unless $refund->is_success(); + + my $paybatch = "$processor:". $refund->authorization; + $paybatch .= ':'. $refund->order_number + if $refund->can('order_number') && $refund->order_number; + + while ( $cust_pay && $cust_pay->unapplied < $amount ) { + my @cust_bill_pay = $cust_pay->cust_bill_pay; + last unless @cust_bill_pay; + my $cust_bill_pay = pop @cust_bill_pay; + my $error = $cust_bill_pay->delete; + last if $error; + } + + my $cust_refund = new FS::cust_refund ( { + 'custnum' => $self->custnum, + 'paynum' => $options{'paynum'}, + 'refund' => $amount, + '_date' => '', + 'payby' => $bop_method2payby{$options{method}}, + 'payinfo' => $payinfo, + 'paybatch' => $paybatch, + 'reason' => $options{'reason'} || 'card or ACH refund', + } ); + my $error = $cust_refund->insert; + if ( $error ) { + $cust_refund->paynum(''); #try again with no specific paynum + my $error2 = $cust_refund->insert; + if ( $error2 ) { + # gah, even with transactions. + my $e = 'WARNING: Card/ACH refunded but database not updated - '. + "error inserting refund ($processor): $error2". + " (previously tried insert with paynum #$options{'paynum'}" . + ": $error )"; + warn $e; + return $e; + } + } + + ''; #no error + +} + =item batch_card OPTION => VALUE... Adds a payment for this invoice to the pending credit card batch (see diff --git a/FS/FS/cust_pay_pending.pm b/FS/FS/cust_pay_pending.pm index bbabd247e..fba19ea19 100644 --- a/FS/FS/cust_pay_pending.pm +++ b/FS/FS/cust_pay_pending.pm @@ -191,6 +191,7 @@ sub check { #|| $self->ut_textn('statustext') || $self->ut_anything('statustext') #|| $self->ut_money('cust_balance') + || $self->ut_hexn('session_id') || $self->ut_foreign_keyn('paynum', 'cust_pay', 'paynum' ) || $self->payinfo_check() #payby/payinfo/paymask/paydate ; @@ -215,6 +216,18 @@ sub check { $self->SUPER::check; } +=item cust_main + +Returns the associated L record if any. Otherwise returns false. + +=cut + +sub cust_main { + my $self = shift; + qsearchs('cust_main', { custnum => $self->custnum } ); +} + + #these two are kind-of false laziness w/cust_main::realtime_bop #(currently only used when resolving pending payments manually) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index dd6db1be9..7c8656c09 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -439,9 +439,7 @@ replace methods. sub check { my $self = shift; - $self->locationnum('') - if defined($self->locationnum) && length($self->locationnum) - && ( $self->locationnum == 0 || $self->locationnum == -1 ); + $self->locationnum('') if !$self->locationnum || $self->locationnum == -1; my $error = $self->ut_numbern('pkgnum') diff --git a/FS/FS/payby.pm b/FS/FS/payby.pm index b54e5d938..30a03ddfe 100644 --- a/FS/FS/payby.pm +++ b/FS/FS/payby.pm @@ -48,28 +48,33 @@ tie %hash, 'Tie::IxHash', tinyname => 'card', shortname => 'Credit card', longname => 'Credit card (automatic)', + realtime => 1, }, 'DCRD' => { tinyname => 'card', shortname => 'Credit card', longname => 'Credit card (on-demand)', cust_pay => 'CARD', #this is a customer type only, payments are CARD... + realtime => 1, }, 'CHEK' => { tinyname => 'check', shortname => 'Electronic check', longname => 'Electronic check (automatic)', + realtime => 1, }, 'DCHK' => { tinyname => 'check', shortname => 'Electronic check', longname => 'Electronic check (on-demand)', cust_pay => 'CHEK', #this is a customer type only, payments are CHEK... + realtime => 1, }, 'LECB' => { tinyname => 'phone bill', shortname => 'Phone bill billing', longname => 'Phone bill billing', + realtime => 1, }, 'BILL' => { tinyname => 'billing', @@ -131,6 +136,15 @@ sub can_payby { return 1; } +sub realtime { # can use realtime payment facilities + my( $self, $payby ) = @_; + + return 0 unless $hash{$payby}; + return 0 unless exists( $hash{$payby}->{realtime} ); + + return $hash{$payby}->{realtime}; +} + sub payby2longname { my $self = shift; map { $_ => $hash{$_}->{longname} } $self->payby; @@ -157,6 +171,7 @@ sub longname { %payby2bop = ( 'CARD' => 'CC', 'CHEK' => 'ECHECK', + 'MCRD' => 'CC', ); sub payby2bop { diff --git a/FS/FS/payment_gateway.pm b/FS/FS/payment_gateway.pm index 35b4f0835..bc8b875c3 100644 --- a/FS/FS/payment_gateway.pm +++ b/FS/FS/payment_gateway.pm @@ -1,12 +1,14 @@ package FS::payment_gateway; use strict; -use vars qw( @ISA ); +use vars qw( @ISA $me $DEBUG ); use FS::Record qw( qsearch qsearchs dbh ); use FS::option_Common; use FS::agent_payment_gateway; @ISA = qw( FS::option_Common ); +$me = '[ FS::payment_gateway ]'; +$DEBUG=0; =head1 NAME @@ -37,6 +39,8 @@ currently supported: =item gatewaynum - primary key +=item gateway_namespace - Business::OnlinePayment or Business::OnlineThirdPartyPayment + =item gateway_module - Business::OnlinePayment:: module name =item gateway_username - payment gateway username @@ -110,8 +114,12 @@ sub check { my $error = $self->ut_numbern('gatewaynum') || $self->ut_alpha('gateway_module') + || $self->ut_enum('gateway_namespace', ['Business::OnlinePayment', + 'Business::OnlineThirdPartyPayment', + ] ) || $self->ut_textn('gateway_username') || $self->ut_anything('gateway_password') + || $self->ut_textn('gateway_callback_url') # a bit too permissive || $self->ut_enum('disabled', [ '', 'Y' ] ) #|| $self->ut_textn('gateway_action') ; @@ -131,6 +139,10 @@ sub check { $self->gateway_action('Normal Authorization'); } + # this little kludge mimics FS::CGI::popurl + $self->gateway_callback_url($self->gateway_callback_url. '/') + if ( $self->gateway_callback_url && $self->gateway_callback_url !~ /\/$/ ); + $self->SUPER::check; } @@ -186,6 +198,41 @@ sub disable { } +=item namespace_description + +returns a friendly name for the namespace + +=cut + +my %namespace2description = ( + '' => 'Direct', + 'Business::OnlinePayment' => 'Direct', + 'Business::OnlineThirdPartyPayment' => 'Hosted', +); + +sub namespace_description { + $namespace2description{shift->gateway_namespace} || 'Unknown'; +} + +# _upgrade_data +# +# Used by FS::Upgrade to migrate to a new database. +# +# + +sub _upgrade_data { + my ($class, %opts) = @_; + my $dbh = dbh; + + warn "$me upgrading $class\n" if $DEBUG; + + foreach ( qsearch( 'payment_gateway', { 'gateway_namespace' => '' } ) ) { + $_->gateway_namespace('Business::OnlinePayment'); #defaulting + my $error = $_->replace; + die "$class had error during upgrade replacement: $error" if $error; + } +} + =back =head1 BUGS diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index 580ca7334..3ede27cd9 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -39,6 +39,7 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'process_payment_order_pkg' => 'MyAccount/process_payment_order_pkg', 'process_payment_order_renew' => 'MyAccount/process_payment_order_renew', 'process_prepay' => 'MyAccount/process_prepay', + 'realtime_collect' => 'MyAccount/realtime_collect', 'list_pkgs' => 'MyAccount/list_pkgs', #add to ss (added?) 'list_svcs' => 'MyAccount/list_svcs', #add to ss (added?) 'list_svc_usage' => 'MyAccount/list_svc_usage', @@ -58,6 +59,7 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'signup_info' => 'Signup/signup_info', 'domain_select_hash' => 'Signup/domain_select_hash', # expose? 'new_customer' => 'Signup/new_customer', + 'capture_payment' => 'Signup/capture_payment', 'agent_login' => 'Agent/agent_login', 'agent_logout' => 'Agent/agent_logout', 'agent_info' => 'Agent/agent_info', diff --git a/fs_selfservice/FS-SelfService/cgi/change_pay.html b/fs_selfservice/FS-SelfService/cgi/change_pay.html index 2bea9550b..7283cb850 100644 --- a/fs_selfservice/FS-SelfService/cgi/change_pay.html +++ b/fs_selfservice/FS-SelfService/cgi/change_pay.html @@ -51,10 +51,11 @@ 'LECB' => qq/Phone Bill Billing/, 'BILL' => qq/Billing/, 'COMP' => qq/Complimentary/, + 'PREP' => qq/Prepaid Card/, 'PREPAY' => qq/Prepaid Card/, ); tie my %options, 'Tie::IxHash', (); - foreach my $payby_option ( @paybys ) { + foreach my $payby_option ( grep { exists( $payby_index{$_} ) } @paybys ) { $options{$payby_option} = $payby_index{$payby_option}; } $options{$payby} = $payby_index{$payby} diff --git a/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html b/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html new file mode 100755 index 000000000..042b8b37c --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html @@ -0,0 +1,38 @@ +My Account +MyAccount

+ + + + + + +<%= $url = "$selfurl?session=$session_id;action="; ''; %> +<%= include('myaccount_menu') %> + +Pay now

+ +<%= if ( $error ) { + $OUT .= qq!$error

!; +}else{ + $OUT .= <
+ Your transaction reference number is $reference

+
+EOF + + my %itemhash = @collectitems; + foreach my $input (keys %itemhash) { + $OUT .= qq!!; + } + + $OUT .= qq!!; + $OUT .= qq!
!; +} +%> + + diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html index cb5ed352e..c9ca0c5f0 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html @@ -8,7 +8,11 @@ Hello <%= $name %>!

<%= $small_custview %>
<%= if ( $balance > 0 ) { - $OUT .= qq! Make a payment

!; + if (scalar(grep $_, @hide_payment_field)) { + $OUT .= qq! Make a payment

!; + } else { + $OUT .= qq! Make a payment

!; + } } %> <%= if ( @open_invoices ) { diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html index ec5a8fa42..cc9f255ce 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html @@ -18,14 +18,34 @@ my @menu = ( if ( 1 ) { #XXXFIXME "enable selfservice prepay features" flag or something, eventually per-pkg or something really fancy - push @menu, ( - { title=>'Recharge my account with a credit card', - url=>'make_payment', indent=>2 }, - { title=>'Recharge my account with a check', - url=>'make_ach_payment', indent=>2 }, - { title=>'Recharge my account with a prepaid card', - url=>'recharge_prepay', indent=>2 }, - ); + #XXXFIXME still a bit sloppy for multi-gateway of differing namespace + my $i = 0; + while($i < scalar(@cust_paybys)) { last if $cust_paybys[$i] =~ /^CARD/; $i++ } + if ( $cust_paybys[$i] =~ /^CARD/ ) { + push @menu, { title => 'Recharge my account with a credit card', + url => $hide_payment_fields[$i] + ? 'make_thirdparty_payment&payby_method=CC' + : 'make_payment', + indent => 2, + } + } + + $i = 0; + while($i < scalar(@cust_paybys)) { last if $cust_paybys[$i] =~ /^CHEK/; $i++ } + if ( $cust_paybys[$i] =~ /^CHEK/ ) { + push @menu, { title => 'Recharge my account with a check', + url => $hide_payment_field[$i] + ? 'make_thirdparty_payment&payby_method=ECHECK' + : 'make_ach_payment', + indent => 2, + } + } + + push @menu, { title => 'Recharge my account with a prepaid card', + url => 'recharge_prepay', + indent => 2, + } + if grep(/^PREP/, @cust_paybys); } diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index 865b5cecd..bb3db12c6 100644 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -10,7 +10,7 @@ use HTML::Entities; use Date::Format; use Number::Format 1.50; use FS::SelfService qw( login_info login customer_info edit_info invoice - payment_info process_payment + payment_info process_payment realtime_collect process_prepay list_pkgs order_pkg signup_info order_recharge part_svc_info provision_acct provision_external @@ -72,7 +72,7 @@ $session_id = $cgi->param('session'); #order|pw_list XXX ??? $cgi->param('action') =~ - /^(myaccount|view_invoice|make_payment|make_ach_payment|payment_results|ach_payment_results|recharge_prepay|recharge_results|logout|change_bill|change_ship|change_pay|process_change_bill|process_change_ship|process_change_pay|customer_order_pkg|process_order_pkg|customer_change_pkg|process_change_pkg|process_order_recharge|provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|view_usage|view_usage_details|view_support_details|change_password|process_change_password)$/ + /^(myaccount|view_invoice|make_payment|make_ach_payment|make_thirdparty_payment|payment_results|ach_payment_results|recharge_prepay|recharge_results|logout|change_bill|change_ship|change_pay|process_change_bill|process_change_ship|process_change_pay|customer_order_pkg|process_order_pkg|customer_change_pkg|process_change_pkg|process_order_recharge|provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|view_usage|view_usage_details|view_support_details|change_password|process_change_password)$/ or die "unknown action ". $cgi->param('action'); my $action = $1; @@ -98,6 +98,7 @@ warn "processing template $action\n" do_template($action, { 'session_id' => $session_id, 'action' => $action, #so the menu knows what tab we're on... + %{ payment_info( 'session_id' => $session_id ) }, # cust_paybys for the menu %{$result} }); @@ -472,6 +473,12 @@ sub ach_payment_results { } +sub make_thirdparty_payment { + $cgi->param('payby_method') =~ /^(CC|ECHECK)$/ + or die "illegal payby method"; + realtime_collect( 'session_id' => $session_id, 'method' => $1 ); +} + sub recharge_prepay { customer_info( 'session_id' => $session_id ); } diff --git a/fs_selfservice/FS-SelfService/cgi/signup.cgi b/fs_selfservice/FS-SelfService/cgi/signup.cgi index 47857f0a7..12452e686 100755 --- a/fs_selfservice/FS-SelfService/cgi/signup.cgi +++ b/fs_selfservice/FS-SelfService/cgi/signup.cgi @@ -8,11 +8,12 @@ use vars qw( @payby $cgi $init_data $ieak_file $ieak_template $signup_html $signup_template $success_html $success_template + $collect_html $collect_template $decline_html $decline_template ); use subs qw( print_form print_okay print_decline - success_default decline_default + success_default collect_default decline_default ); use CGI; #use CGI::Carp qw(fatalsToBrowser); @@ -35,6 +36,9 @@ $signup_html = -e 'signup.html' $success_html = -e 'success.html' ? 'success.html' : '/usr/local/freeside/success.html'; +$collect_html = -e 'collect.html' + ? 'collect.html' + : '/usr/local/freeside/collect.html'; $decline_html = -e 'decline.html' ? 'decline.html' : '/usr/local/freeside/decline.html'; @@ -97,6 +101,24 @@ if ( -e $success_html ) { or die $Text::Template::ERROR; } +if ( -e $collect_html ) { + my $collect_txt = Text::Template::_load_text($collect_html) + or die $Text::Template::ERROR; + $collect_txt =~ /^(.*)$/s; #untaint the template source - it's trusted + $collect_txt = $1; + $collect_template = new Text::Template ( TYPE => 'STRING', + SOURCE => $collect_txt, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} else { + $collect_template = new Text::Template ( TYPE => 'STRING', + SOURCE => &collect_default, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} + if ( -e $decline_html ) { my $decline_txt = Text::Template::_load_text($decline_html) or die $Text::Template::ERROR; @@ -122,9 +144,10 @@ $init_data = signup_info( 'agentnum' => $agentnum, 'reg_code' => uc(scalar($cgi->param('reg_code'))), ); -if ( ( defined($cgi->param('magic')) && $cgi->param('magic') eq 'process' ) - || ( defined($cgi->param('action')) && $cgi->param('action') eq 'process_signup' ) - ) { +my $magic = $cgi->param('magic') || ''; +my $action = $cgi->param('action') || ''; + +if ( $magic eq 'process' || $action eq 'process_signup' ) { $error = ''; @@ -218,6 +241,10 @@ if ( ( defined($cgi->param('magic')) && $cgi->param('magic') eq 'process' ) if ( $error eq '_decline' ) { print_decline(); + } elsif ( $error eq '_collect' ) { + map { $cgi->param($_, $rv->{$_}) } + qw( popup_url reference collectitems amount ); + print_collect(); } elsif ( $error ) { #fudge the snarf info no strict 'refs'; @@ -230,6 +257,16 @@ if ( ( defined($cgi->param('magic')) && $cgi->param('magic') eq 'process' ) ); } +} elsif ( $magic eq 'success' || $action eq 'success' ) { + + $cgi->param('username', 'username'); #hmmm temp kludge + $cgi->param('_password', 'password'); + print_okay( map { /^([\w ]+)$/ ? ( $_ => $1 ) : () } $cgi->param ); #hmmm + +} elsif ( $magic eq 'decline' || $action eq 'decline' ) { + + print_decline(); + } else { $error = ''; print_form; @@ -258,6 +295,27 @@ sub print_form { ); } +sub print_collect { + + $error = "Error: $error" if $error; + + my $r = { + $cgi->Vars, + %{$init_data}, + 'error' => $error, + }; + + $r->{pkgpart} ||= $r->{default_pkgpart}; + + $r->{referral_custnum} = $r->{'ref'}; + $r->{self_url} = $cgi->self_url; + + print $cgi->header( '-expires' => 'now' ), + $collect_template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi', + HASH => $r + ); +} + sub print_decline { print $cgi->header( '-expires' => 'now' ), $decline_template->fill_in(); @@ -369,6 +427,37 @@ Package: <%= $pkg %>
END } +sub collect_default { #html to use if there is a collect phase + <<'END'; +Pay now +Pay now

+ + + + + + +You are about to contact our payment processor to pay <%= $amount %> for +<%= $pkg %>.

+Your transaction reference number is <%= $reference %>

+
+<%= + my %itemhash = @collectitems; + foreach my $input (keys %itemhash) { + $OUT .= qq!!; + } +%> + +
+ +END +} + sub decline_default { #html to use if there is a decline <<'END'; Processing error diff --git a/fs_selfservice/FS-SelfService/cgi/signup.html b/fs_selfservice/FS-SelfService/cgi/signup.html index 1b97121c6..ae7b2226a 100755 --- a/fs_selfservice/FS-SelfService/cgi/signup.html +++ b/fs_selfservice/FS-SelfService/cgi/signup.html @@ -245,7 +245,7 @@ HTML::Widgets::SelectLayers->new( form_name => 'dummy', html_between => '', form_action => 'dummy.cgi', - layer_callback => sub { my $layer = shift; return $paybychecked{$layer}. ''; }, + layer_callback => sub { my $layer = shift; return ( shift @hide_payment_fields ? '' : $paybychecked{$layer} ) . ''; }, )->html; diff --git a/fs_selfservice/FS-SelfService/cgi/verify.cgi b/fs_selfservice/FS-SelfService/cgi/verify.cgi new file mode 100755 index 000000000..0f8bfccc8 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/verify.cgi @@ -0,0 +1,175 @@ +#!/usr/bin/perl -T +#!/usr/bin/perl -Tw + +use strict; +use vars qw( $cgi $self_url $error + $verify_html $verify_template + $success_html $success_template + $decline_html $decline_template + ); + +use subs qw( print_verify print_okay print_decline + verify_default success_default decline_default + ); +use CGI; +use Text::Template; +use FS::SelfService qw( capture_payment ); + +$verify_html = -e 'verify.html' + ? 'verify.html' + : '/usr/local/freeside/verify.html'; +$success_html = -e 'verify_success.html' + ? 'success.html' + : '/usr/local/freeside/success.html'; +$decline_html = -e 'verify_decline.html' + ? 'decline.html' + : '/usr/local/freeside/decline.html'; + + +if ( -e $verify_html ) { + my $verify_txt = Text::Template::_load_text($verify_html) + or die $Text::Template::ERROR; + $verify_txt =~ /^(.*)$/s; #untaint the template source - it's trusted + $verify_txt = $1; + $verify_template = new Text::Template ( TYPE => 'STRING', + SOURCE => $verify_txt, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} else { + $verify_template = new Text::Template ( TYPE => 'STRING', + SOURCE => &verify_default, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} + +if ( -e $success_html ) { + my $success_txt = Text::Template::_load_text($success_html) + or die $Text::Template::ERROR; + $success_txt =~ /^(.*)$/s; #untaint the template source - it's trusted + $success_txt = $1; + $success_template = new Text::Template ( TYPE => 'STRING', + SOURCE => $success_txt, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} else { + $success_template = new Text::Template ( TYPE => 'STRING', + SOURCE => &success_default, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} + +if ( -e $decline_html ) { + my $decline_txt = Text::Template::_load_text($decline_html) + or die $Text::Template::ERROR; + $decline_txt =~ /^(.*)$/s; #untaint the template source - it's trusted + $decline_txt = $1; + $decline_template = new Text::Template ( TYPE => 'STRING', + SOURCE => $decline_txt, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} else { + $decline_template = new Text::Template ( TYPE => 'STRING', + SOURCE => &decline_default, + DELIMITERS => [ '<%=', '%>' ], + ) + or die $Text::Template::ERROR; +} + +$cgi = new CGI; + +my $rv = capture_payment( + data => { map { $_ => scalar($cgi->param($_)) } $cgi->param }, + url => $cgi->self_url, +); + +$error = $rv->{error}; + +if ( $error eq '_decline' ) { + print_decline(); +} elsif ( $error ) { + print_verify(); +} else { + print_okay(%$rv); +} + + +sub print_verify { + + $error = "Error: $error" if $error; + + my $r = { $cgi->Vars, 'error' => $error }; + + $r->{self_url} = $cgi->self_url; + + print $cgi->header( '-expires' => 'now' ), + $verify_template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi', + HASH => $r + ); +} + +sub print_decline { + print $cgi->header( '-expires' => 'now' ), + $decline_template->fill_in(); +} + +sub print_okay { + my %param = @_; + + my @success_url = split '/', $cgi->url(-path); + pop @success_url; + + my $success_url = join '/', @success_url; + if ($param{session_id}) { + my $session_id = lc($param{session_id}); + $success_url .= "/selfservice.cgi?action=myaccount&session=$session_id"; + } else { + $success_url .= '/signup.cgi?action=success'; + } + + print $cgi->header( '-expires' => 'now' ), + $success_template->fill_in( HASH => { success_url => $success_url } ); +} + +sub success_default { #html to use if you don't specify a success file + <<'END'; +Signup successful +Signup successful

+Thanks for signing up! +

+ + +END +} + +sub verify_default { #html to use for verification response + <<'END'; +Processing error +Processing error

+There has been an error processing your account. Please contact customer +support. + +END +} + +sub decline_default { #html to use if there is a decline + <<'END'; +Processing error +Processing error

+There has been an error processing your account. Please contact customer +support. + +END +} + +# subs for the templates... + +package FS::SelfService::_signupcgi; +use HTML::Entities; + diff --git a/httemplate/browse/payment_gateway.html b/httemplate/browse/payment_gateway.html index 848c58a82..a06e5cf7c 100644 --- a/httemplate/browse/payment_gateway.html +++ b/httemplate/browse/payment_gateway.html @@ -10,17 +10,21 @@ }, 'count_query' => $count_query, 'header' => [ '#', + 'Type', 'Gateway', 'Username', 'Password', 'Action', + 'URL', 'Options', ], 'fields' => [ 'gatewaynum', + 'namespace_description', $gateway_sub, 'gateway_username', sub { ' - '; }, 'gateway_action', + 'gateway_callback_url', $options_sub, ], ) diff --git a/httemplate/edit/payment_gateway.html b/httemplate/edit/payment_gateway.html index e3893cf49..2b108f857 100644 --- a/httemplate/edit/payment_gateway.html +++ b/httemplate/edit/payment_gateway.html @@ -1,132 +1,122 @@ -<% include("/elements/header.html","$action Payment gateway", menubar( - 'View all payment gateways' => $p. 'browse/payment_gateway.html', -)) %> - -<% include('/elements/error.html') %> - -
- -Gateway #<% $payment_gateway->gatewaynum || "(NEW)" %> - -<% ntable('#cccccc', 2, '') %> - - - Gateway: - -% if ( $payment_gateway->gatewaynum ) { - - - <% $payment_gateway->gateway_module %> - -% } else { - - - +<% include( 'elements/edit.html', + 'table' => 'payment_gateway', + 'name_singular' => 'Payment gateway', + 'viewall_dir' => 'browse', + 'fields' => $fields, + 'field_callback' => $field_callback, + 'labels' => { + 'gatewaynum' => 'Gateway #', + 'gateway_module' => 'Gateway', + 'gateway_username' => 'Username', + 'gateway_password' => 'Password', + 'gateway_action' => 'Action', + 'gateway_options' => 'Options: (Name/Value pairs, one element per line)', + 'gateway_callback_url' => 'Callback URL', + }, + ) +%> + + + <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my $payment_gateway; -if ( $cgi->param('error') ) { - $payment_gateway = new FS::payment_gateway ( { - map { $_, scalar($cgi->param($_)) } fields('payment_gateway') - } ); -} elsif ( $cgi->keywords ) { - my($query) = $cgi->keywords; - $query =~ /^(\d+)$/; - $payment_gateway = qsearchs( 'payment_gateway', { 'gatewaynum' => $1 } ); -} else { #adding - $payment_gateway = new FS::payment_gateway {}; -} -my $action = $payment_gateway->gatewaynum ? 'Edit' : 'Add'; -#my $hashref = $payment_gateway->hashref; +my %modules = ( + '2CheckOut' => 'Business::OnlinePayment', + 'AuthorizeNet' => 'Business::OnlinePayment', + 'BankOfAmerica' => 'Business::OnlinePayment', + 'Beanstream' => 'Business::OnlinePayment', + 'Capstone' => 'Business::OnlinePayment', + 'Cardstream' => 'Business::OnlinePayment', + 'CashCow' => 'Business::OnlinePayment', + 'CyberSource' => 'Business::OnlinePayment', + 'eSec' => 'Business::OnlinePayment', + 'eSelectPlus' => 'Business::OnlinePayment', + 'Exact' => 'Business::OnlinePayment', + 'iAuthorizer' => 'Business::OnlinePayment', + 'Interswitchng' => 'Business::OnlineThirdPartyPayment', + 'IPaymentTPG' => 'Business::OnlinePayment', + 'Jettis' => 'Business::OnlinePayment', + 'LinkPoint' => 'Business::OnlinePayment', + 'MerchantCommerce' => 'Business::OnlinePayment', + 'Network1Financial' => 'Business::OnlinePayment', + 'OCV' => 'Business::OnlinePayment', + 'OpenECHO' => 'Business::OnlinePayment', + 'PayConnect' => 'Business::OnlinePayment', + 'PayflowPro' => 'Business::OnlinePayment', + 'PaymentsGateway' => 'Business::OnlinePayment', + 'PXPost' => 'Business::OnlinePayment', + 'SecureHostingUPG' => 'Business::OnlinePayment', + 'Skipjack' => 'Business::OnlinePayment', + 'StGeorge' => 'Business::OnlinePayment', + 'SurePay' => 'Business::OnlinePayment', + 'TCLink' => 'Business::OnlinePayment', + 'TransactionCentral' => 'Business::OnlinePayment', + 'TransFirsteLink' => 'Business::OnlinePayment', + 'VirtualNet' => 'Business::OnlinePayment', +); + +my @actions = ( + 'Normal Authorization', + 'Authorization Only', + 'Authorization Only, Post Authorization', + ); + +my $fields = [ + { + field => 'gateway_namespace', + type => 'hidden', + curr_value_callback => sub { my($cgi, $object, $fref) = @_; + $modules{$object->gateway_module} + || 'Business::OnlinePayment' + }, + }, + { + field => 'gateway_module', + type => 'select', + options => [ sort { lc($a) cmp lc ($b) } keys %modules ], + onchange => 'setNamespace', + }, + 'gateway_username', + 'gateway_password', + { + field => 'gateway_action', + type => 'select', + options => \@actions, + }, + 'gateway_callback_url', + { + field => 'gateway_options', + type => 'textarea', + curr_value_callback => sub { my($cgi, $object, $fref) = @_; + join("\r", $object->options ); + }, + }, + ]; + +my $field_callback = sub { + my ($cgi, $object, $field_hashref ) = @_; + if ($object->gatewaynum) { + if ( $field_hashref->{field} eq 'gateway_module' ) { + $field_hashref->{type} = 'fixed'; + } + } +}; diff --git a/httemplate/edit/process/payment_gateway.html b/httemplate/edit/process/payment_gateway.html index b16bc3d27..812c988c5 100644 --- a/httemplate/edit/process/payment_gateway.html +++ b/httemplate/edit/process/payment_gateway.html @@ -1,35 +1,22 @@ -%if ( $error ) { -% $cgi->param('error', $error); -<% $cgi->redirect(popurl(2). "payment_gateway.html?". $cgi->query_string ) %> -%} else { -<% $cgi->redirect(popurl(3). "browse/payment_gateway.html") %> -%} +<% include( 'elements/process.html', + 'table' => 'payment_gateway', + 'viewall_dir' => 'browse', + 'args_callback' => $args_callback, + ) +%> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my $gatewaynum = $cgi->param('gatewaynum'); +my $args_callback = sub { + my ( $cgi, $new ) = @_; -my $old = qsearchs('payment_gateway',{'gatewaynum'=>$gatewaynum}) if $gatewaynum; + my @options = split(/\r?\n/, $cgi->param('gateway_options') ); + pop @options + if scalar(@options) % 2 && $options[-1] =~ /^\s*$/; + (@options) +}; -my $new = new FS::payment_gateway ( { - map { - $_, scalar($cgi->param($_)); - } fields('payment_gateway') -} ); - -my @options = split(/\r?\n/, $cgi->param('gateway_options') ); -pop @options - if scalar(@options) % 2 && $options[-1] =~ /^\s*$/; -my %options = @options; - -my $error; -if ( $gatewaynum ) { - $error=$new->replace($old, \%options); -} else { - $error=$new->insert(\%options); - $gatewaynum=$new->getfield('gatewaynum'); -} diff --git a/httemplate/elements/tr-textarea.html b/httemplate/elements/tr-textarea.html new file mode 100644 index 000000000..fb41ac38f --- /dev/null +++ b/httemplate/elements/tr-textarea.html @@ -0,0 +1,25 @@ +<% include('tr-td-label.html', @_ ) %> + + > + + + + + + + +<%init> + +my %opt = @_; + +my $onchange = $opt{'onchange'} + ? 'onChange="'. $opt{'onchange'}. '(this)"' + : ''; + +my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : ''; +my $curr_value = $opt{'curr_value'}; + + -- cgit v1.2.1 From 7bc780834a604a2e678d028f875fd4b546412cfb Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 11 Mar 2009 08:46:21 +0000 Subject: quick list of area codes and a kludge to print DA numbers for all of them --- bin/print-directory_assist | 12 ++ etc/areacodes.txt | 353 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 365 insertions(+) create mode 100755 bin/print-directory_assist create mode 100644 etc/areacodes.txt diff --git a/bin/print-directory_assist b/bin/print-directory_assist new file mode 100755 index 000000000..210a16c60 --- /dev/null +++ b/bin/print-directory_assist @@ -0,0 +1,12 @@ +#!/usr/bin/perl -w + +use strict; + +my $acs = `cut -c1-3 ../etc/areacodes.txt`; + +my $plus = ''; +foreach my $npa ( split(/\n/, $acs ) ) { + warn $npa; + $plus .= $npa. '5551212 '; +} +print "$plus\n"; diff --git a/etc/areacodes.txt b/etc/areacodes.txt new file mode 100644 index 000000000..e214db1b9 --- /dev/null +++ b/etc/areacodes.txt @@ -0,0 +1,353 @@ +201 NJ New Jersey (Hackensack, Jersey City, Hoboken and northeast New Jersey, overlays with 551) +202 DC District of Columbia (all of Washington, DC) +203 CT Connecticut (Bridgeport, New Haven, Waterbury and southwestern Connecticut, overlays with 475) +204 MB Manitoba (all of Manitoba) +205 AL Alabama (Birmingham, Tuscaloosa and central and western Alabama) +206 WA Washington (Seattle, Sea-Tac, Ballard, Madison, Capitol Hill and central Seattle neighborhoods) +207 ME Maine (all of Maine) +208 ID Idaho (all of Idaho) +209 CA California (Stockton, Merced, Modesto, San Andreas and central California) +210 TX Texas (San Antonio area) +212 NY New York (New York City Manhattan area, overlays with 646 and 917) +213 CA California (Downtown Los Angeles area only) +214 TX Texas (Dallas area, overlays with 469 and 972) +215 PA Pennsylvania (Philadelphia area, overlays with 267 and 445) +216 OH Ohio (Cleveland area) +217 IL Illinois (Champaign, Decatur, Urbana, Springfield and central Illinois) +218 MN Minnesota (Duluth, Thief River Falls, Brainerd, International Falls and northern Minnesota) +219 IN Indiana (Gary, Valparaiso, Michigan City, Goodland, Fowler and northwestern Indiana) +224 IL Illinois (Waukegan, Des Plaines, northwest Chicago suburbs and northeastern Illinois, overlays with 847) +225 LA Louisiana (Baton Rouge, New Roads, White Castle and central eastern Louisiana) +226 ON Ontario (London, Windsor and southwestern Ontario, overlays with 519) +228 MS Mississippi (Gulfport, Pascagoula, Biloxi, Bay St Louis and southern Mississippi gulf coast) +229 GA Georgia (Albany, Valdosta, Bainbridge, Americus, Fitzgerald and southwestern Georgia) +231 MI Michigan (Traverse City, Ludington, Muskegon, Petoskey and northwestern Michigan) +234 OH Ohio (Youngstown, Warren, Akron, Canton and northeastern Ohio, overlays with 330) +239 FL Florida (Fort Meyers, Naples, Everglades and southwestern Florida) +240 MD Maryland (Hagerstown, Rockville, Cumberland and western Maryland, overlays with 301) +242 BAHAMAS (all of Bahamas) +246 BARBADOS (all of Barbados) +248 MI Michigan (Troy, Oakland County, Pontiac, Southfield, Rochester Hills and northwestern Detroit suburbs, overlays with 947) +250 BC British Columbia (all except Vancouver area) +251 AL Alabama (Mobile, Jackson and southwestern Alabama) +252 NC North Carolina (Greenville, Kitty Hawk, Rocky Mount and northeastern North Carolina) +253 WA Washington (Tacoma, Auburn, Puyallup, Enumclaw, Spanaway and south Seattle suburbs) +254 TX Texas (Waco, Killeen, Belton, Stephenville and north central Texas) +256 AL Alabama (Florence, Huntsville, Gadsden, Anniston and northern and eastern Alabama) +260 IN Indiana (Fort Wayne, Decatur, Angola, Wabash and northeastern Indiana) +262 WI Wisconsin (Menomonee Falls, Waukesha, Racine and southeastern Wisconsin excluding Milwaukee area) +264 ANGUILLA (all of Anguilla) +267 PA Pennsylvania (Philadelphia area, overlays with 215 and 445) +268 ANTIGUA and BARBUDA (all of Antigua and Barbuda) +269 MI Michigan (Battle Creek, Benton Harbor, Allegan, Hastings, Kalamazoo, St Joseph, and southwestern Michigan) +270 KY Kentucky (Paducah, Bowling Green, Hopkinsville, Owensboro and western Kentucky) +276 VA Virginia (Abingdon, Wytheville, Martinsville, Bluefield and western Virginia) +281 TX Texas (Spring, Katy, Houston area, overlays with 713 and 832) +284 BRITISH VIRGIN ISLANDS (all of the British Virgin Islands) +289 ON Ontario (Hamilton, Toronto suburbs and central southeastern Ontario, overlays with 905) +301 MD Maryland (Hagerstown, Rockville, Cumberland and western Maryland, overlays with 240) +302 DE Delaware (all of Delaware) +303 CO Colorado (Boulder, Longmont, Aurora, Denver and central Colorado, overlays with 720) +304 WV West Virginia (all of West Virginia) +305 FL Florida (Miami, Homestead, Coral Gables, Key West and southeastern Florida, overlays with 786) +306 SK Saskatchewan (all of Saskatchewan) +307 WY Wyoming (all of Wyoming) +308 NE Nebraska (North Platte, Scottsbluff, McCook, Grand Island and western Nebraska) +309 IL Illinois (Peoria, Moline, Rock Island, Galesburg and central western Illinois) +310 CA California (Malibu, Torrance, Beverley Hills, Santa Monica, Catalina and western Los Angeles suburbs, overlays with 424) +311 NON-EMERGENCY ACCESS +312 IL Illinois (downtown central Chicago area) +313 MI Michigan (Dearborn, Detroit and inner Detroit suburbs) +314 MO Missouri (St Louis, Florissant, Crestwood, Affton and surrounding suburbs) +315 NY New York (Watertown, Utica, Syracuse and north central New York) +316 KS Kansas ( Wichita, Augusta, El Dorado, Mulvane and the Wichita surrounding area) +317 IN Indiana (Indianapolis, Greenwood, Mooresville, Beech Grove and central Indiana) +318 LA Louisiana (Shreveport, Monroe, Alexandria, Fisher, Tallulah and northern Louisiana) +319 IA Iowa (Burlington, Iowa City, Cedar Rapids, Waterloo and east central and southeastern Iowa) +320 MN Minnesota (St Cloud, Morris, Hutchinson, Sandstone, Appleton and central Minnesota) +321 FL Florida (Orlando, Cocoa Beach, St Cloud and central eastern Florida, overlays with 407) +323 CA California (Florence and Los Angeles excluding downtown Los Angeles) +325 TX Texas (Abilene, San Angelo, Albany, Comanche, Snyder, Ozona and west central Texas) +330 OH Ohio (Youngstown, Warren, Akron, Canton and northeastern Ohio, overlays with 234) +331 IL Illinois (Aurora, Batavia, Geneva and western Chicago suburbs, overlays with 630) +334 AL Alabama ( Montgomery, Auburn, Dothan, Selma and southeastern Alabama) +336 NC North Carolina (Winston-Salem, Greensboro, North Wilkesboro and northwest North Carolina) +337 LA Louisiana (Leesville, Lake Charles, Lafayette, De Ridder and southwestern Louisiana) +339 MA Massachusetts (Saugus, Norwood and east central Massachusetts, overlays with 781) +340 US VIRGIN ISLANDS (all of the US Virgin Islands) +345 CAYMAN ISLANDS (all of the Cayman Islands) +347 NY New York (Flushing, Jamaica, Brooklyn, Staten Island, Bronx and Queens, overlays with 718 and 917) +351 MA Massachusetts (Fitchburg, Peabody and northeastern Massachusetts, overlays with 978) +352 FL Florida (Gainesville, Ocala, Inverness, Dunnellon and central Florida) +360 WA Washington (Bellingham, Vancouver, Aberdeen, Olympia and western Washington except Seattle area) +361 TX Texas (Corpus Christi, Victoria, George West and southeastern Texas) +385 UT Utah (North and south of Salt Lake City including Ogden, Provo, Bountiful and Spanish Fork) +386 FL Florida (Daytona Beach, Lake City, Live Oak, Crescent City and northern and eastern Florida) +401 RI Rhode Island (all of Rhode Island) +402 NE Nebraska (Valentine, Lincoln, Norfolk, Omaha, Superior, Crofton and eastern Nebraska) +403 AB Alberta (Calgary, Banff, Red Deer, Medicine Hat, Lethbridge and southern Alberta) +404 GA Georgia (central Atlanta area, overlays with 470 and 678) +405 OK Oklahoma (Oklahoma City, Edmond, Norman, Shawnee, Chickasha and central Oklahoma) +406 MT Montana (all of Montana) +407 FL Florida (Orlando, Cocoa Beach, St Cloud and central eastern Florida, overlays with 321) +408 CA California (Los Gatos, Milpitas, Sunnyvale, Cupertino and San Jose area) +409 TX Texas (Beaumont, Galveston, Port Arthur, Jasper and southeastern Texas) +410 MD Maryland (Annapolis, Baltimore, Salisbury and eastern Maryland, overlays with 443) +411 LOCAL DIRECTORY ASSISTANCE +412 PA Pennsylvania (Pittsburgh area, McKeesport, Braddock, Duquesne, overlays with 878) +413 MA Massachusetts (Pittsfield, Springfield, Holyoke, Greenfield and western Massachusetts) +414 WI Wisconsin (Milwaukee, Greenfield, Oak Creek and Milwaukee suburbs) +415 CA California (Sausalito, San Rafael, Novato, San Quentin, San Francisco and bay area) +416 ON Ontario (Toronto area, overlays with 647) +417 MO Missouri (Joplin, Springfield, West Plains, Lamar, Lebanon and southwestern Missouri) +418 QC Quebec (Quebec and eastern Quebec) +419 OH Ohio (Toledo, Mansfield, Lima, Bryan, Sandusky, Bowling Green and northwestern Ohio, overlays with 567) +423 TN Tennessee (Bristol, Sweetwater, Chattanooga, and southeastern and north eastern Tennessee) +424 CA California (Malibu, Torrance, Beverley Hills, Santa Monica, Catalina and western Los Angeles suburbs, overlays with 310) +425 WA Washington (north and east Seattle suburbs including Everett, Bellevue, Redmond, Renton and Issaquah) +430 TX Texas (Tyler, Sherman, Longview, Palestine and northeastern Texas, overlays with 903) +432 TX Texas (Alpine, Midland, Odessa, Big Bend, Seminole, Comstock and west central Texas)< Central Time Zone> +434 VA Virginia (Lynchburg, Danville, South Hill, Charlottesville and south central Virginia) +435 UT Utah (Logan, St George, Moab and all of Utah excluding Salt Lake City, Ogden, Provo and central Utah) +438 QC Quebec (Montreal area, overlays with 514) +440 OH Ohio (Elyria, Lorain, Oberlin, Wellington and north central Ohio) +441 BERMUDA (all of Bermuda) +443 MD Maryland (Annapolis, Baltimore, Salisbury and eastern Maryland, overlays with 410) +450 QC Quebec (central southern Quebec excluding Montreal) +456 INTERNATIONAL INBOUND +469 TX Texas (Dallas area, overlays with 214 and 972) +470 GA Georgia (Atlanta, Gainesville and north central Georgia, overlays with 404 and 678 and 770) +473 GRENADA (all of Grenada) +475 CT Connecticut ( Bridgeport, New Haven, Waterbury and southwestern Connecticut, overlays with 203) +478 GA Georgia (Macon, Warner Robins, Swainsboro, Wadley, Milledgeville, Perry and central Georgia) +479 AR Arkansas (Fort Smith, Fayetteville and northwestern Arkansas) +480 AZ Arizona (Chandler, eastern Phoenix area and eastern Phoenix suburbs only) +484 PA Pennsylvania (Reading, Allentown, Chester and southeastern Pennsylvania, overlays with 610 and 835) +500 PERSONAL COMMUNICATIONS SERVICES +501 AR Arkansas (Little Rock, Hot Springs and central Arkansas) +502 KY Kentucky (Louisville, Frankfort, Shelbyville and north central Kentucky) +503 OR Oregon (Portland, Salem, Tillamook, Astoria and northwestern Oregon, overlays with 971) +504 LA Louisiana (New Orleans, Kenner, Metairie and surrounding areas) +505 NM New Mexico (Albuquerque, Farmington, Gallup, Santa Fe and northwestern New Mexico) +506 NB New Brunswick (all of New Brunswick) +507 MN Minnesota (Rochester, Mankato, Worthington, Marshall and southern Minnesota) +508 MA Massachusetts (Worcester, New Bedford and southeastern Massachusetts, overlays with 774) +509 WA Washington (Spokane, Yakima, Walla Walla, Moses Lake, Ellensburg and eastern Washington) +510 CA California (Hayward, Berkeley, Oakland, Richmond and Fremont areas) +512 TX Texas (Austin, Lampasas, Bastrop, Milam and central Texas) +513 OH Ohio (Cincinnati, Middletown, Hamilton, Norwood, Lebanon and southwestern Ohio) +514 QC Quebec (Montreal area, overlays with 438) +515 IA Iowa (Des Moines, Ames, Fort Dodge, Jefferson, Algona, Indianola and north central Iowa) +516 NY New York (Nassau County, Levittown, Hicksville, Massapequa and western Long Island) +517 MI Michigan (Jackson, Lansing, Howell, Deerfield, Addison and south central Michigan) +518 NY New York (Plattsburgh, Saranac Lake, Albany and northeastern New York) +519 ON Ontario (London, Windsor and southwestern Ontario, overlays with 226) +520 AZ Arizona (Tucson and southeastern Arizona) +530 CA California (Alturas, Chico, Redding, Placerville, Truckee and northeastern California) +540 VA Virginia (Roanoke, Harrisonburg, Winchester, Fredericksburg and northern Virginia) +541 OR Oregon (Medford, Eugene, Ontario, Burns and all of Oregon except northwestern Oregon) +551 NJ New Jersey (Hackensack, Jersey City, and northeast New Jersey, overlays with 201) +559 CA California (Fresno, Madera, Hanford, Visalia and central California) +561 FL Florida (West Palm Beach, Boca Raton, Boynton Beach, Delray Beach, Belleglade and central eastern Florida) +562 CA California (Long Beach, Lakewood, Bellflower and southwestern Los Angeles suburbs) +563 IA Iowa (Decorah, Dubuque, Clinton, Davenport and eastern and northeastern Iowa) +567 OH Ohio (Toledo, Mansfield, Lima, Bryan, Sandusky and northwestern Ohio, overlays with 419) +570 PA Pennsylvania (Scranton, Williamsport, Wilkes-Barre, Susquehanna and northeastern Pennsylvania) +571 VA Virginia (Alexandria, Washington DC suburbs, Arlington and northeastern Virginia, overlays with 703) +573 MO Missouri (Jefferson City, Hannibal, Poplar Bluff and eastern Missouri excluding St Louis) +574 IN Indiana (South Bend, Logansport, Elkhart, Nappanee and north central Indiana) +575 NM New Mexico (Carlsbad, Las Cruces, Roswell, Silver City, Taos and southern and eastern New Mexico) +580 OK Oklahoma (Guymon, Hugo, Enid, Lawton, Ardmore, Elk City and southern and western Oklahoma) +585 NY New York (Rochester, Wellsville, Batavia, Olean and western New York) +586 MI Michigan (Port Huron, Flint, Flushing, Warren and eastern Michigan, overlays with 810) +600 CANADA/SERVICES +601 MS Mississippi (Jackson, Meridian, Natchez, McComb, Hattiesburg and central Mississippi, overlays with 769) +602 AZ Arizona (Central Phoenix only) +603 NH New Hampshire (all of New Hampshire) +604 BC British Columbia (Vancouver, Richmond, Abbotsford, Whistler and southwestern BC, overlays with 778) +605 SD South Dakota (all of South Dakota) +606 KY Kentucky (Ashland, Hazard, Somerset, London, Corbin, Pikeville, Maysville and eastern Kentucky) +607 NY New York (Binghamton, Elmira, Bath, Norwich and south central New York) +608 WI Wisconsin (Madison, La Crosse, Platteville, Janesville and southwestern Wisconsin) +609 NJ New Jersey (Atlantic City, Brown Mills, Trenton, and central & southeastern New Jersey) +610 PA Pennsylvania (Reading, Allentown, Chester and southeastern Pennsylvania, overlays with 484 and 835) +611 REPAIR SERVICE +612 MN Minnesota (Central Minneapolis, Fort Snelling, St Anthony and Richfield) +613 ON Ontario (Ottawa and southeastern Ontario) +614 OH Ohio (Columbus area) +615 TN Tennessee (Nashville, Murfreesboro, Springfield, Lebanon, Dickson and north central Tennessee) +616 MI Michigan ( Grand Rapids, Holland, Greenville, Grandhaven, Zeeland, and southwestern Michigan) +617 MA Massachusetts (Boston, Cambridge and east central Massachusetts, overlays with 857) +618 IL Illinois (Carbondale, Alton, Centralia, Mount Vernon and southern Illinois) +619 CA California (National City, Chula Vista, Imperial Beach, Otay and the San Diego area) +620 KS Kansas (Dodge City, Great Bend, Parsons, Liberal and southern Kansas) +623 AZ Arizona (Buckeye, Peoria, western Phoenix area and western Phoenix suburbs only) +626 CA California (Arcadia, Temple City, Covina, Pasadena and eastern Los Angeles suburbs) +630 IL Illinois (Aurora, Batavia, Geneva and western Chicago suburbs, overlays with 331) +631 NY New York (Manorville, Huntington, Lindenhurst, Islip, Deer Park and Eastern Long Island) +636 MO Missouri (Chesterfield, Union, De Soto, Troy and east central Missouri) +641 IA Iowa (Mason City, Oskaloosa, Creston, Pella, Ottumwa, Britt, Clear Lake, Fairfield and central Iowa) +646 NY New York (New York City Manhattan area, overlays with 212 and 917) +647 ON Ontario (Toronto area, overlays with 416) +649 TURKS & CAICOS (all of Turks and Caicos) +650 CA California (San Mateo, Palo Alto, Redwood City, Menlo Park and southern San Francisco suburbs) +651 MN Minnesota (St Paul, Lindstrom, Red Wing, Hastings and east central Minnesota) +660 MO Missouri (Marshall, Sedalia, Macon, Trenton, Maryville and north central Missouri) +661 CA California (Bakersfield, Mojave, Santa Clarita, Palmdale and south central California) +662 MS Mississippi (Greenville, Tupelo, Winona, Columbus, Holly Springs and northern Mississippi) +664 MONTSERRAT (all of Montserrat) +670 COMMONWEALTH OF THE NORTHERN MARIANA ISLANDS (all of CNMI including Saipan) +671 GUAM (all of Guam) +678 GA Georgia (Atlanta, Gainesville, Griffin and north central Georgia, overlays 404 and and 470 and 770) +682 TX Texas (Fort Worth, Arlington, Grandview, Weatherford, Rhome, overlays with 817) +684 AMERICAN SAMOA (all of American Samoa including Pago Pago) +700 INTEREXCHANGE CARRIER SERVICES +701 ND North Dakota (all of North Dakota) +702 NV Nevada (Las Vegas, Henderson and extreme southern Nevada) +703 VA Virginia (Alexandria, Washington DC suburbs, Arlington and northeastern Virginia, overlays with 571) +704 NC North Carolina (Charlotte, Kingstown and south central North Carolina, overlays with 980) +705 ON Ontario (North Bay and northeastern Ontario) +706 GA Georgia (Augusta, Columbus, Lagrange, Rome, Dalton and northern and west central Georgia, overlays with 762) +707 CA California (Santa Rosa, Fort Bragg, Crescent City, Eureka, Ukiah and northwestern California) +708 IL Illinois (Chicago Heights, Tinley Park and southern Chicago suburbs) +709 NF Newfoundland (all of Newfoundland) +710 US GOVERNMENT +711 TRS ACCESS +712 IA Iowa (Estherville, Council Bluffs, Sioux City, Sheldon, Denison and western Iowa) +713 TX Texas (Spring, Katy, Houston area, overlays with 281 and 832) +714 CA California (Huntington Beach, Orange, Garden Grove, Tustin, Anaheim and northern Orange County) +715 WI Wisconsin (Rhinelander, Wausau, Eau Claire, Rice Lake, Ashland and northern Wisconsin) +716 NY New York (Buffalo, Jamestown, Niagara Falls, Tonawanda and western New York) +717 PA Pennsylvania (Harrisburg, Gettysburg, Lancaster, York and south central Pennsylvania) +718 NY New York (Flushing, Jamaica, Brooklyn, Staten Island, Bronx and Queens, overlays with 347 and 917) +719 CO Colorado (Leadville, Pueblo, Colorado Springs, Trinidad and southeastern Colorado) +720 CO Colorado (Boulder, Longmont, Aurora, Denver and central Colorado, overlays with 303) +724 PA Pennsylvania (New Castle, Washington, Uniontown and south western Pennsylvania, overlays with 878) +727 FL Florida (Clearwater, St Petersburg, Dunedin and the west central Florida gulf coast) +731 TN Tennessee (Union City, Jackson, Dyersburg, Paris, Bolivar and western Tennessee) +732 NJ New Jersey (New Brunswick, Neptune, Lakewood, and east central New Jersey, overlays with 848) +734 MI Michigan (Ann Arbor, Monroe, Wayne, Ypsilanti and southwestern Detroit suburbs) +740 OH Ohio (Jackson, Lancaster, Marietta, Cambridge, Zanesville, New Castle and southeastern Ohio) +754 FL Florida (Fort Lauderdale, Pompano Beach, overlays with 954) +757 VA Virginia (Hampton, Norfolk, Williamsburg, Newport News, Virginia Beach and southeastern Virginia) +758 ST LUCIA (all of St Lucia) +760 CA California (Bishop, Ridgecrest, Indio, Barstow, El Centro, Palm Springs and southeastern California) +762 GA Georgia (Augusta, Columbus, Lagrange, Rome, Dalton and northern and west central Georgia, overlays with 706) +763 MN Minnesota (Maple Grove, Monticello, Elk River, Fridley, Blaine, and northwest Minneapolis area) +765 IN Indiana (Lafayette, Marion, Muncie, Richmond and central Indiana excluding Indianapolis) +767 DOMINICA (all of Dominica) +769 MS Mississippi (Jackson, Meridian, Natchez, McComb, Hattiesburg and central Mississippi, overlays with 601) +770 GA Georgia (Marietta, Cedartown, and north central Georgia, overlays with 470 and 678) +772 FL Florida (Vero Beach, Port Saint Lucie, Fort Pierce, Sebastian, Stuart and central eastern Florida) +773 IL Illinois (Chicago excluding downtown Chicago) +774 MA Massachusetts (Worcester and southeastern Massachusetts, overlays with 508) +775 NV Nevada (Reno, Elko, Ely and all of Nevada excluding Las Vegas and extreme southern Nevada) +778 BC British Columbia (Vancouver, Richmond, Abbotsford and southwestern BC overlays with 604) +779 IL Illinois (La Salle, De Kalb, Rockford, Freeport and northern Illinois excluding Chicago area, overlays with 815) +780 AB Alberta (Edmonton, Jasper, Grande Prairie, Peace River and northern Alberta) +781 MA Massachusetts (Saugus, Norwood and east central Massachusetts, overlays with 339) +784 ST VINCENT AND THE GRENADINES (all of St Vincent and the Grenadines) +785 KS Kansas (Colby, Topeka, Salina, Manhattan, Lawrence and northern Kansas) +786 FL Florida (Miami, Homestead, Coral Gables, Key West and southeastern Florida, overlays with 305) +787 PUERTO RICO (all of Puerto Rico, overlays with 939) +800 TOLL FREE SERVICES +801 UT Utah (Salt Lake City, Salt Lake County, Midvale, Alta, Magna, Kearns Holladay, and central Utah) +802 VT Vermont (all of Vermont) +803 SC South Carolina (Columbia, Rock Hill, Sumter, Aiken and central South Carolina) +804 VA Virginia (Richmond, Petersburg, West Point, Chester and east central Virginia) +805 CA California (Santa Barbara, San Luis Obispo, Lompoc and central western coastal California) +806 TX Texas (Amarillo, Lubbock, Canadian, Perryton, Shamrock, Dalhart and Texas panhandle) +807 ON Ontario (Thunder Bay and western Ontario) +808 HI Hawaii (all of Hawaii) +809 DOMINICAN REPUBLIC (all of the Dominican Republic, overlays with 829) +810 MI Michigan (Port Huron, Flint, Flushing, Warren and eastern Michigan, overlays with 586) +811 BUSINESS OFFICE +812 IN Indiana (Evansville, New Albany, Terre Haute, Bloomington and southern Indiana) +813 FL Florida (Tampa, Hillsborough, Plant City, Port Tampa and central western Florida) +814 PA Pennsylvania (Erie, Warren, Altoona, Johnstown, Meyersdale and central and northwestern Pennsylvania) +815 IL Illinois (La Salle, De Kalb, Rockford, Freeport and northern Illinois excluding Chicago area, overlays with 779) +816 MO Missouri (Kansas City, St Joseph, Independence, Harrisonville and west central Missouri) +817 TX Texas (Fort Worth, Arlington, Grandview, Weatherford, Rhome, overlays with 682) +818 CA California ( Glendale, San Fernando, Burbank and northern Los Angeles suburbs) +819 QC Quebec (Western Quebec) +822 TOLL FREE SERVICES +828 NC North Carolina (Asheville, Brevard, Morganton, Murphy and western North Carolina) +829 DOMINICAN REPUBLIC (all of the Dominican Republic, overlays with 809) +830 TX Texas (Uvalde, New Braunfels, Kerrville, Eagle Pass and southwest Texas) +831 CA California (Salinas, Hollister, Monterey, Santa Cruz and central western coastal California) +832 TX Texas (Spring, Katy, Houston area, overlays with 281 and 713) +833 TOLL FREE SERVICES +835 PA Pennsylvania (Reading, Allentown, and southeastern Pennsylvania, overlays with 484 and 610) +843 SC South Carolina (Florence, Myrtle Beach, Charleston, Hilton Head Island and eastern South Carolina) +844 TOLL FREE SERVICES +845 NY New York ( Poughkeepsie, Middletown, West Point, Newburgh and southeastern New York) +847 IL Illinois (Waukegan, Des Plaines, northwest Chicago suburbs and northeastern Illinois, overlays with 224) +848 NJ New Jersey (New Brunswick, Neptune, and east central New Jersey, overlays with 732) +850 FL Florida ( Pensacola, Tallahassee, Panama City and the Florida panhandle) +855 TOLL FREE SERVICES +856 NJ New Jersey (Vineland, Cherry Hill, Camden, Millville, and southwestern New Jersey) +857 MA Massachusetts (Boston, Cambridge and east central Massachusetts, overlays with 617) +858 CA California (Del Mar, La Jolla and northern San Diego suburbs) +859 KY Kentucky (Lexington, Richmond, Danville, Covington, Mount Sterling and north central Kentucky) +860 CT Connecticut (Bristol, Hartford, Norwich and northern and eastern Connecticut, overlays with 959) +862 NJ New Jersey (Newark, Paterson and northwestern New Jersey, overlays with 973) +863 FL Florida (Avon Park, Clewiston, Lakeland, Bartow, Sebring, Winter Haven and south central Florida) +864 SC South Carolina (Greenville, Spartanburg, Anderson and western South Carolina) +865 TN Tennessee (Knoxville, Newport, Jefferson City, Oak Ridge and east central Tennessee) +866 TOLL FREE SERVICES +867 YK Yukon, Northwest Territories, and Nunavut (Yukon, Northwest Territories and Nunavut) +868 TRINIDAD AND TOBAGO (all of Trinidad and Tobago) +869 ST KITTS AND NEVIS (all of St Kitts and Nevis) +870 AR Arkansas (Texarkana, Mountain Home, Pine Bluff and southern, eastern and northeastern Arkansas) +876 JAMAICA (all of Jamaica) +877 TOLL FREE SERVICES +878 PA Pennsylvania (Pittsburgh, New Castle, and southwestern Pennsylvania, overlays with 412 and 724) +880 PAID 800 SERVICE FROM CARIBBEAN TO THE US AND CANADA OR FROM CANADA TO THE US +881 PAID 888 SERVICE FROM CARIBBEAN TO THE US AND CANADA OR FROM CANADA TO THE US +882 PAID 877 SERVICE FROM CARIBBEAN TO THE US AND CANADA OR FROM CANADA TO THE US +888 TOLL FREE SERVICES +900 900 NUMBER PAY PER CALL SERVICES +901 TN Tennessee (Memphis, Covington, Somerville and south western Tennessee) +902 NS Nova Scotia (all of Nova Scotia and Prince Edward Island) +903 TX Texas (Tyler, Sherman, Longview, Palestine and northeastern Texas, overlays with 430) +904 FL Florida (Jacksonville, St Augustine, Starke, Green Cove Springs and northeastern Florida) +905 ON Ontario (Hamilton, Toronto suburbs and central southeastern Ontario, overlays with 289) +906 MI Michigan (Ironwood, Marquette, Sault Ste Marie, Escanaba and upper Michigan) +907 AK Alaska (all of Alaska) +908 NJ New Jersey (Washington, Elizabeth, Warren, Plainfield and west central New Jersey) +909 CA California (San Bernardino, Ontario, Pomona, Chino, Arrowhead and Big Bear Lake areas) +910 NC North Carolina (Fayetteville, Wilmington, Lumberton and southeastern North Carolina) +911 EMERGENCY +912 GA Georgia ( Savannah, Vidalia, Waycross, Brunswick, Douglas and southeastern Georgia) +913 KS Kansas (Kansas City, Overland Park, Paola Leavenworth and extreme eastern Kansas) +914 NY New York (White Plains, Yonkers, Pelham, Westchester, Peekskill and southeastern New York) +915 TX Texas (El Paso, Dell City, Guadalupe Peak, Sierra Blanca, and far western Texas) +916 CA California (Sacramento area) +917 NY New York (New York City Manhattan area, overlays with 212 and 646) +918 OK Oklahoma (Tulsa, Bartlesville, McAlester, Muskogee, Henrietta and northeastern Oklahoma) +919 NC North Carolina (Raleigh, Durham, Chapel Hill, Oxford and north central North Carolina) +920 WI Wisconsin (Sheboygan, Oshkosh, Green Bay, Manitowoc, Fond Du Lac and eastern Wisconsin) +925 CA California (Pleasanton, Martinez, Concord, Livermore, Walnut Creek and Dublin areas) +928 AZ Arizona (Flagstaff, Kingman, Prescott, Yuma and northern and western Arizona) +931 TN Tennessee (Clarksville, Columbia, Manchester, Cookeville and central Tennessee) +936 TX Texas (Nacogdoches, Lufkin, Conroe, Huntsville, Center and southeastern Texas) +937 OH Ohio (Marysville, Springfield, Dayton, Hillsboro and southwestern Ohio excluding Cincinnati area) +939 PUERTO RICO (all of Puerto Rico, overlays with 787) +940 TX Texas (Vernon, Wichita Falls, Denton, Gainesville, Decatur and north central Texas) +941 FL Florida ( Bradenton, Port Charlotte, Sarasota, Punta Gorda and the west central Florida coast) +947 MI Michigan (Troy, Oakland County, Pontiac, Southfield, Rochester Hills and northwestern Detroit suburbs, overlays with 248) +949 CA California (Laguna Niguel, Irvine, El Toro, Newport Beach, Corona Del Mar and southern Orange County) +951 CA California (Riverside, Corona, Murrieta, Perris, San Jacinto and Temecula areas) +952 MN Minnesota (Bloomington, Minnetonka, Chaska and southwest Minneapolis area) +954 FL Florida (Fort Lauderdale, Pompano Beach, overlays with 754) +956 TX Texas (Laredo, Brownsville, McAllen, Harlingen and southern Texas) +959 CT Connecticut (Bristol, Hartford, Norwich and northern and eastern Connecticut, overlays with 860) +970 CO Colorado (Aspen, Durango, Grand Junction, Fort Collins and northern and western Colorado) +971 OR Oregon (Portland, Salem, Hillsboro, Beaverton and northwestern Oregon, overlays with 503) +972 TX Texas (Dallas area, overlays with 214 and 469) +973 NJ New Jersey (Newark, Paterson and northwestern New Jersey, overlays with 862) +978 MA Massachusetts (Fitchburg, Peabody and northeastern Massachusetts, overlays with 351) +979 TX Texas (Wharton, Bryan, Bay City, College Station, Lake Jackson and southeastern Texas) +980 NC North Carolina (Charlotte, Kingstown and south central North Carolina, overlays with 704) +985 LA Louisiana (Houma, Slidell and southeastern Louisiana excluding New Orleans) +989 MI Michigan (Alpena, Mt Pleasant, Bay City, Saginaw, Midland, Owosso and central Michigan) -- cgit v1.2.1 From 3cc8babac7a9a1ae9f6b20979a7787a94761a6ec Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 11 Mar 2009 08:57:01 +0000 Subject: comma --- bin/print-directory_assist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/print-directory_assist b/bin/print-directory_assist index 210a16c60..4c5e4a861 100755 --- a/bin/print-directory_assist +++ b/bin/print-directory_assist @@ -7,6 +7,6 @@ my $acs = `cut -c1-3 ../etc/areacodes.txt`; my $plus = ''; foreach my $npa ( split(/\n/, $acs ) ) { warn $npa; - $plus .= $npa. '5551212 '; + $plus .= $npa. '5551212,'; } print "$plus\n"; -- cgit v1.2.1 From d3c80e75b62421ea742cbe4547305227f8c10bea Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 11 Mar 2009 09:41:51 +0000 Subject: add cdr display with accountcode included, RT#4405 --- FS/FS/cdr.pm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index 67c5c1c2a..f0082279e 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -464,6 +464,10 @@ my %export_names = ( 'name' => 'Default with source', 'invoice_header' => 'Caller,Date,Time,Number,Destination,Duration,Price', }, + 'accountcode_default' => { + 'name' => 'Default plus accountcode', + 'invoice_header' => 'Caller,Date,Time,Number,Destination,Duration,Price', + }, ); my %export_formats = ( @@ -528,6 +532,11 @@ my %export_formats = ( ], ); $export_formats{'source_default'} = [ 'src', @{ $export_formats{'default'} }, ]; +$export_formats{'accountcode_default'} = + [ @{ $export_formats{'default'} }[0,1], + 'accountcode', + @{ $export_formats{'default'} }[2..5], + ]; sub downstream_csv { my( $self, %opt ) = @_; -- cgit v1.2.1 From 2ea58badb5e0e2985a796f8b614912db9b6e43bf Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 11 Mar 2009 10:04:00 +0000 Subject: add previous_balance-summary_only config, RT#4404 --- FS/FS/Conf.pm | 7 +++++++ FS/FS/cust_bill.pm | 52 ++++++++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 3921afdaa..3f150e1e7 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2485,6 +2485,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'previous_balance-summary_only', + 'section' => 'billing', + 'description' => 'Only show a single line summarizing the total previous balance rather than one line per invoice.', + 'type' => 'checkbox', + }, + { 'key' => 'usps_webtools-userid', 'section' => 'UI', diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 704b3504a..1f78d72f4 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -2080,33 +2080,37 @@ sub print_generic { push @sections, { 'description' => '', 'subtotal' => '' }; } - foreach my $line_item ( $conf->exists('disable_previous_balance') - ? () - : $self->_items_previous - ) + unless ( $conf->exists('disable_previous_balance') + || $conf->exists('previous_balance-summary_only') + ) { - my $detail = { - ext_description => [], - }; - $detail->{'ref'} = $line_item->{'pkgnum'}; - $detail->{'quantity'} = 1; - $detail->{'section'} = $previous_section; - $detail->{'description'} = &$escape_function($line_item->{'description'}); - if ( exists $line_item->{'ext_description'} ) { - @{$detail->{'ext_description'}} = map { - &$escape_function($_); - } @{$line_item->{'ext_description'}}; + + foreach my $line_item ( $self->_items_previous ) { + + my $detail = { + ext_description => [], + }; + $detail->{'ref'} = $line_item->{'pkgnum'}; + $detail->{'quantity'} = 1; + $detail->{'section'} = $previous_section; + $detail->{'description'} = &$escape_function($line_item->{'description'}); + if ( exists $line_item->{'ext_description'} ) { + @{$detail->{'ext_description'}} = map { + &$escape_function($_); + } @{$line_item->{'ext_description'}}; + } + $detail->{'amount'} = ( $old_latex ? '' : $money_char). + $line_item->{'amount'}; + $detail->{'product_code'} = $line_item->{'pkgpart'} || 'N/A'; + + push @detail_items, $detail; + push @buf, [ $detail->{'description'}, + $money_char. sprintf("%10.2f", $line_item->{'amount'}), + ]; } - $detail->{'amount'} = ( $old_latex ? '' : $money_char). - $line_item->{'amount'}; - $detail->{'product_code'} = $line_item->{'pkgpart'} || 'N/A'; - - push @detail_items, $detail; - push @buf, [ $detail->{'description'}, - $money_char. sprintf("%10.2f", $line_item->{'amount'}), - ]; + } - + if ( @pr_cust_bill && !$conf->exists('disable_previous_balance') ) { push @buf, ['','-----------']; push @buf, [ 'Total Previous Balance', -- cgit v1.2.1 From 64916ad920572e19351df79127d4822fab57f621 Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 13 Mar 2009 18:22:21 +0000 Subject: prevent more duplicate MACs from sneaking in in the interim --- FS/FS/svc_broadband.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm index b808527a1..eb2964635 100755 --- a/FS/FS/svc_broadband.pm +++ b/FS/FS/svc_broadband.pm @@ -217,6 +217,10 @@ sub check { ; return $error if $error; + #redundant, but prevents further problems until column constraint in place + return "MAC already in use" + if scalar( qsearch( 'svc_broadband', { 'mac_addr', $self->mac_addr } ) ); + if($self->speed_up < 0) { return 'speed_up must be positive'; } if($self->speed_down < 0) { return 'speed_down must be positive'; } -- cgit v1.2.1 From dae7ad7ff2a06ae047de9fd6d88e74edc526b4ad Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Mar 2009 23:44:38 +0000 Subject: fix emailed logos to come from db config, not old files, RT#3093 / RT#4963 --- FS/FS/cust_bill.pm | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 1f78d72f4..c8384c009 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -660,21 +660,22 @@ sub generate_email { my $from = $1 || 'example.com'; my $content_id = join('.', rand()*(2**32), $$, time). "\@$from"; - my $path = "$FS::UID::conf_dir/conf.$FS::UID::datasrc"; - my $file; + my $logo; + my $agentnum = $self->cust_main->agentnum; if ( defined($args{'template'}) && length($args{'template'}) - && -e "$path/logo_". $args{'template'}. ".png" + && $conf->exists( 'logo_'. $args{'template'}. '.png', $agentnum ) ) { - $file = "$path/logo_". $args{'template'}. ".png"; + $logo = 'logo_'. $args{'template'}. '.png'; } else { - $file = "$path/logo.png"; + $logo = "logo.png"; } + my $image_data = $conf->config_binary( $logo, $agentnum); my $image = build MIME::Entity 'Type' => 'image/png', 'Encoding' => 'base64', - 'Path' => $file, + 'Data' => $image_data, 'Filename' => 'logo.png', 'Content-ID' => "<$content_id>", ; -- cgit v1.2.1 From 5cf0508a1ec3dafaeef8a4bd206ef5e5b51235c8 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Mar 2009 07:33:06 +0000 Subject: cust_main::payment_info, for ClientAPI::MyAccount --- FS/FS/cust_main.pm | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 2bad5ec3e..69126956a 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -6032,6 +6032,86 @@ sub in_transit_payments { sprintf( "%.2f", $in_transit_payments ); } +=item payment_info + +Returns a hash of useful information for making a payment. + +=over 4 + +=item balance + +Current balance. + +=item payby + +'CARD' (credit card - automatic), 'DCRD' (credit card - on-demand), +'CHEK' (electronic check - automatic), 'DCHK' (electronic check - on-demand), +'LECB' (Phone bill billing), 'BILL' (billing), or 'COMP' (free). + +=back + +For credit card transactions: + +=over 4 + +=item card_type 1 + +=item payname + +Exact name on card + +=back + +For electronic check transactions: + +=over 4 + +=item stateid_state + +=back + +=cut + +sub payment_info { + my $self = shift; + + my %return = (); + + $return{balance} = $self->balance; + + $return{payname} = $self->payname + || ( $self->first. ' '. $self->get('last') ); + + $return{$_} = $self->get($_) for qw(address1 address2 city state zip); + + $return{payby} = $self->payby; + $return{stateid_state} = $self->stateid_state; + + if ( $self->payby =~ /^(CARD|DCRD)$/ ) { + $return{card_type} = cardtype($self->payinfo); + $return{payinfo} = $self->paymask; + + @return{'month', 'year'} = $self->paydate_monthyear; + + } + + if ( $self->payby =~ /^(CHEK|DCHK)$/ ) { + my ($payinfo1, $payinfo2) = split '@', $self->paymask; + $return{payinfo1} = $payinfo1; + $return{payinfo2} = $payinfo2; + $return{paytype} = $self->paytype; + $return{paystate} = $self->paystate; + + } + + #doubleclick protection + my $_date = time; + $return{paybatch} = "webui-MyAccount-$_date-$$-". rand() * 2**32; + + %return; + +} + =item paydate_monthyear Returns a two-element list consisting of the month and year of this customer's -- cgit v1.2.1 From dc24b4b7e2e41dbb3039e9ce367b018fef299ade Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Mar 2009 10:30:26 +0000 Subject: we're not a disk drive manufacturer, don't use halfass base-10 megs/gigs --- FS/FS/UI/bytecount.pm | 4 ++-- httemplate/edit/prepay_credit.cgi | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/FS/FS/UI/bytecount.pm b/FS/FS/UI/bytecount.pm index 0891e6d68..0ddc7545c 100644 --- a/FS/FS/UI/bytecount.pm +++ b/FS/FS/UI/bytecount.pm @@ -32,9 +32,9 @@ sub bytecount_unexact { return("$bc bytes") if ($bc < 1000); return(sprintf("%.2f Kbytes", $bc/1024)) - if ($bc < 1000000); + if ($bc < 1048576); return(sprintf("%.2f Mbytes", $bc/1048576)) - if ($bc < 1000000000); + if ($bc < 1073741824); return(sprintf("%.2f Gbytes", $bc/1073741824)); } diff --git a/httemplate/edit/prepay_credit.cgi b/httemplate/edit/prepay_credit.cgi index 9e1c30ba6..ed404b7cd 100644 --- a/httemplate/edit/prepay_credit.cgi +++ b/httemplate/edit/prepay_credit.cgi @@ -97,14 +97,14 @@ tie my %multiplier, 'Tie::IxHash', tie my %bytemultiplier, 'Tie::IxHash', 1 => 'bytes', - 1000 => 'Kbytes', - 1000000 => 'Mbytes', - 1000000000 => 'Gbytes', + 1024 => 'Kbytes', + 1048576 => 'Mbytes', + 1073741824 => 'Gbytes', ; $cgi->param('multiplier', '60') unless $cgi->param('multiplier'); -$cgi->param('upmultiplier', '1000000') unless $cgi->param('upmultiplier'); -$cgi->param('downmultiplier', '1000000') unless $cgi->param('downmultiplier'); -$cgi->param('totalmultiplier','1000000') unless $cgi->param('totalmultiplier'); +$cgi->param('upmultiplier', '1048576') unless $cgi->param('upmultiplier'); +$cgi->param('downmultiplier', '1048576') unless $cgi->param('downmultiplier'); +$cgi->param('totalmultiplier','1048576') unless $cgi->param('totalmultiplier'); -- cgit v1.2.1 From a53dc991aa0c04c5b9a5d06256100af5e93943e1 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Mar 2009 10:34:30 +0000 Subject: apply byte values from prepaid cards as well as time value, RT#4995 --- httemplate/misc/process/recharge_svc.html | 103 +++++++++++++++--------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/httemplate/misc/process/recharge_svc.html b/httemplate/misc/process/recharge_svc.html index 147b9533a..8c4d13e63 100755 --- a/httemplate/misc/process/recharge_svc.html +++ b/httemplate/misc/process/recharge_svc.html @@ -1,62 +1,13 @@ -%unless ($error) { -% -% my ($amount, $seconds, $up, $down, $total) = (0, 0, 0, 0, 0); -% #should probably use payby.pm but whatever -% if ($payby eq 'PREP') { -% $error = $cust_main->get_prepay($prepaid, \$amount, \$seconds, \$up, \$down, \$total) -% || $svc_acct->increment_seconds($seconds) -% || $svc_acct->increment_upbytes($up) -% || $svc_acct->increment_downbytes($down) -% || $svc_acct->increment_totalbytes($total) -% || $cust_main->insert_cust_pay_prepay( $amount, $prepaid ); -% } elsif ( $payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP)$/ ) { -% my $part_pkg = $svc_acct->cust_svc->cust_pkg->part_pkg; -% $amount = $part_pkg->option('recharge_amount', 1); -% my %rhash = map { $_ =~ /^recharge_(.*)$/; $1, $part_pkg->option($_) } -% grep { $part_pkg->option($_, 1) } -% qw ( recharge_seconds recharge_upbytes recharge_downbytes -% recharge_totalbytes ); -% -% my $description = "Recharge"; -% $description .= " $rhash{seconds}s" if $rhash{seconds}; -% $description .= " $rhash{upbytes} up" if $rhash{upbytes}; -% $description .= " $rhash{downbytes} down" if $rhash{downbytes}; -% $description .= " $rhash{totalbytes} total" if $rhash{totalbytes}; -% -% $error = $cust_main->charge($amount, "Recharge " . $svc_acct->label, -% $description, $part_pkg->taxclass); -% -% if ($part_pkg->option('recharge_reset', 1)) { -% $error ||= $svc_acct->set_usage(\%rhash); -% }else{ -% $error ||= $svc_acct->recharge(\%rhash); -% } -% -% my $old_balance = $cust_main->balance; -% $error ||= $cust_main->bill; -% $error ||= $cust_main->apply_payments_and_credits; -% my $bill_error = $cust_main->collect('realtime' => 1) unless $error; -% $error ||= "Failed to collect - $bill_error" -% if $cust_main->balance > $old_balance && $cust_main->balance > 0 -% && $payby ne 'BILL'; -% -% } else { -% $error = "fatal error - unknown payby: $payby"; -% } -%} -% %if ($error) { % $cgi->param('error', $error); -% $dbh->rollback if $oldAutoCommit; -% print $cgi->redirect(popurl(2). "recharge_svc.html?". $cgi->query_string ); -%} -%$dbh->commit or die $dbh->errstr if $oldAutoCommit; -% +<% cgi->redirect(popurl(2). "recharge_svc.html?". $cgi->query_string ) %> +%} else { <% header("Package recharged") %> +%} <%init> my $conf = new FS::Conf; @@ -89,4 +40,52 @@ my $oldAutoCommit = $FS::UID::AutoCommit; local $FS::UID::AutoCommit = 0; my $dbh = dbh; +unless ($error) { + + #should probably use payby.pm but whatever + if ($payby eq 'PREP') { + $error = $cust_main->recharge_prepay( $prepaid ); + } elsif ( $payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP)$/ ) { + my $part_pkg = $svc_acct->cust_svc->cust_pkg->part_pkg; + $amount = $part_pkg->option('recharge_amount', 1); + my %rhash = map { $_ =~ /^recharge_(.*)$/; $1, $part_pkg->option($_) } + grep { $part_pkg->option($_, 1) } + qw ( recharge_seconds recharge_upbytes recharge_downbytes + recharge_totalbytes ); + + my $description = "Recharge"; + $description .= " $rhash{seconds}s" if $rhash{seconds}; + $description .= " $rhash{upbytes} up" if $rhash{upbytes}; + $description .= " $rhash{downbytes} down" if $rhash{downbytes}; + $description .= " $rhash{totalbytes} total" if $rhash{totalbytes}; + + $error = $cust_main->charge($amount, "Recharge " . $svc_acct->label, + $description, $part_pkg->taxclass); + + if ($part_pkg->option('recharge_reset', 1)) { + $error ||= $svc_acct->set_usage(\%rhash); + }else{ + $error ||= $svc_acct->recharge(\%rhash); + } + + my $old_balance = $cust_main->balance; + $error ||= $cust_main->bill; + $error ||= $cust_main->apply_payments_and_credits; + my $bill_error = $cust_main->collect('realtime' => 1) unless $error; + $error ||= "Failed to collect - $bill_error" + if $cust_main->balance > $old_balance && $cust_main->balance > 0 + && $payby ne 'BILL'; + + } else { + $error = "fatal error - unknown payby: $payby"; + } + +} + +if ($error) { + $dbh->rollback if $oldAutoCommit; +} else { + $dbh->commit or die $dbh->errstr if $oldAutoCommit; +} + -- cgit v1.2.1 From fd1bf67102a849280d78a041eff33e87c3cc7179 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Mar 2009 10:46:31 +0000 Subject: fix application of data fields from prepaid cards in addition to time field --- FS/FS/cust_main.pm | 95 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 69126956a..27a617e1a 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -23,6 +23,7 @@ use FS::UID qw( getotaker dbh driver_name ); use FS::Record qw( qsearchs qsearch dbdef ); use FS::Misc qw( generate_email send_email generate_ps do_print ); use FS::Msgcat qw(gettext); +use FS::payby; use FS::cust_pkg; use FS::cust_svc; use FS::cust_bill; @@ -392,7 +393,7 @@ sub insert { my $dbh = dbh; my $prepay_identifier = ''; - my( $amount, $seconds ) = ( 0, 0 ); + my( $amount, $seconds, $upbytes, $downbytes, $totalbytes ) = (0, 0, 0, 0, 0); my $payby = ''; if ( $self->payby eq 'PREPAY' ) { @@ -403,7 +404,13 @@ sub insert { warn " looking up prepaid card $prepay_identifier\n" if $DEBUG > 1; - my $error = $self->get_prepay($prepay_identifier, \$amount, \$seconds); + my $error = $self->get_prepay( $prepay_identifier, + 'amount_ref' => \$amount, + 'seconds_ref' => \$seconds, + 'upbytes_ref' => \$upbytes, + 'downbytes_ref' => \$downbytes, + 'totalbytes_ref' => \$totalbytes, + ); if ( $error ) { $dbh->rollback if $oldAutoCommit; #return "error applying prepaid card (transaction rolled back): $error"; @@ -465,7 +472,13 @@ sub insert { warn " ordering packages\n" if $DEBUG > 1; - $error = $self->order_pkgs($cust_pkgs, \$seconds, %options); + $error = $self->order_pkgs( $cust_pkgs, + %options, + 'seconds_ref' => \$seconds, + 'upbytes_ref' => \$upbytes, + 'downbytes_ref' => \$downbytes, + 'totalbytes_ref' => \$totalbytes, + ); if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -475,6 +488,10 @@ sub insert { $dbh->rollback if $oldAutoCommit; return "No svc_acct record to apply pre-paid time"; } + if ( $upbytes || $downbytes || $totalbytes ) { + $dbh->rollback if $oldAutoCommit; + return "No svc_acct record to apply pre-paid data"; + } if ( $amount ) { warn " inserting initial $payby payment of $amount\n" @@ -701,7 +718,6 @@ sub order_pkg { if $DEBUG; my $cust_pkg = $opt->{'cust_pkg'}; - my $seconds = $opt->{'seconds'}; my $svcs = $opt->{'svcs'} || []; my %svc_options = (); @@ -745,9 +761,12 @@ sub order_pkg { $error = $new_cust_svc->replace($old_cust_svc); } else { $svc_something->pkgnum( $cust_pkg->pkgnum ); - if ( $seconds && $$seconds && $svc_something->isa('FS::svc_acct') ) { - $svc_something->seconds( $svc_something->seconds + $$seconds ); - $$seconds = 0; + if ( $svc_something->isa('FS::svc_acct') ) { + foreach ( grep { $opt->{$_.'_ref'} && ${ $opt->{$_.'_ref'} } } + qw( seconds upbytes downbytes totalbytes ) ) { + $svc_something->$_( $svc_something->$_() + ${ $opt->{$_.'_ref'} } ); + ${ $opt->{$_.'_ref'} } = 0; + } } $error = $svc_something->insert(%svc_options); } @@ -762,7 +781,8 @@ sub order_pkg { } -=item order_pkgs HASHREF, [ SECONDSREF, [ , OPTION => VALUE ... ] ] +#deprecated #=item order_pkgs HASHREF [ , SECONDSREF ] [ , OPTION => VALUE ... ] +=item order_pkgs HASHREF [ , OPTION => VALUE ... ] Like the insert method on an existing record, this method orders multiple packages and included services atomicaly. Pass a Tie::RefHash data structure @@ -776,12 +796,13 @@ example: $cust_pkg => [ $svc_acct ], ... ); - $cust_main->order_pkgs( \%hash, \'0', 'noexport'=>1 ); + $cust_main->order_pkgs( \%hash, 'noexport'=>1 ); Services can be new, in which case they are inserted, or existing unaudited services, in which case they are linked to the newly-created package. -Currently available options are: I and I. +Currently available options are: I, I, I, +I, I, and I. If I is set, all provisioning jobs will have a dependancy on the supplied jobnum (they will not run until the specific job completes). @@ -794,13 +815,18 @@ the B method for each cust_pkg object. Using the B method on the cust_main object is not recommended, as existing services will also be reexported.) +If I, I, I, or I is +provided, the scalars (provided by references) will be incremented by the +values of the prepaid card.` + =cut sub order_pkgs { my $self = shift; my $cust_pkgs = shift; - my $seconds = shift; + my $seconds_ref = ref($_[0]) ? shift : ''; #deprecated my %options = @_; + $seconds_ref ||= $options{'seconds_ref'}; warn "$me order_pkgs called with options ". join(', ', map { "$_: $options{$_}" } keys %options ). "\n" @@ -821,11 +847,14 @@ sub order_pkgs { foreach my $cust_pkg ( keys %$cust_pkgs ) { - my $error = $self->order_pkg( 'cust_pkg' => $cust_pkg, - 'svcs' => $cust_pkgs->{$cust_pkg}, - 'seconds' => $seconds, - 'depend_jobnum' => $options{'depend_jobnum'}, - ); + my $error = $self->order_pkg( + 'cust_pkg' => $cust_pkg, + 'svcs' => $cust_pkgs->{$cust_pkg}, + 'seconds_ref' => $seconds_ref, + map { $_ => $options{$_} } qw( upbytes_ref downbytes_ref totalbytes_ref + depend_jobnum + ) + ); if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -844,13 +873,14 @@ L), specified either by I or as an FS::prepay_credit object. If there is an error, returns the error, otherwise returns false. -Optionally, four scalar references can be passed as well. They will have their -values filled in with the amount, number of seconds, and number of upload and -download bytes applied by this prepaid -card. +Optionally, five scalar references can be passed as well. They will have their +values filled in with the amount, number of seconds, and number of upload, +download, and total bytes applied by this prepaid card. =cut +#the ref bullshit here should be refactored like get_prepay. MyAccount.pm is +#the only place that uses these args sub recharge_prepay { my( $self, $prepay_credit, $amountref, $secondsref, $upbytesref, $downbytesref, $totalbytesref ) = @_; @@ -868,8 +898,13 @@ sub recharge_prepay { my( $amount, $seconds, $upbytes, $downbytes, $totalbytes) = ( 0, 0, 0, 0, 0 ); - my $error = $self->get_prepay($prepay_credit, \$amount, - \$seconds, \$upbytes, \$downbytes, \$totalbytes) + my $error = $self->get_prepay( $prepay_credit, + 'amount_ref' => \$amount, + 'seconds_ref' => \$seconds, + 'upbytes_ref' => \$upbytes, + 'downbytes_ref' => \$downbytes, + 'totalbytes_ref' => \$totalbytes, + ) || $self->increment_seconds($seconds) || $self->increment_upbytes($upbytes) || $self->increment_downbytes($downbytes) @@ -896,13 +931,13 @@ sub recharge_prepay { } -=item get_prepay IDENTIFIER | PREPAY_CREDIT_OBJ , AMOUNTREF, SECONDSREF +=item get_prepay IDENTIFIER | PREPAY_CREDIT_OBJ [ , OPTION => VALUE ... ] Looks up and deletes a prepaid card (see L), specified either by I or as an FS::prepay_credit object. -References to I and I scalars should be passed as arguments -and will be incremented by the values of the prepaid card. +Available options are: I, I, I, I, and I. The scalars (provided by references) will be +incremented by the values of the prepaid card. If the prepaid card specifies an I (see L), it is used to check or set this customer's I. @@ -913,8 +948,7 @@ If there is an error, returns the error, otherwise returns false. sub get_prepay { - my( $self, $prepay_credit, $amountref, $secondsref, - $upref, $downref, $totalref) = @_; + my( $self, $prepay_credit, %opt ) = @_; local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -959,11 +993,8 @@ sub get_prepay { return "removing prepay_credit (transaction rolled back): $error"; } - $$amountref += $prepay_credit->amount; - $$secondsref += $prepay_credit->seconds; - $$upref += $prepay_credit->upbytes; - $$downref += $prepay_credit->downbytes; - $$totalref += $prepay_credit->totalbytes; + ${ $opt{$_.'_ref'} } += $prepay_credit->$_() + for grep $opt{$_.'_ref'}, qw( amount seconds upbytes downbytes totalbytes ); $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; -- cgit v1.2.1 From fcd4ede322d50422e38426908c4ef62611043435 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Mar 2009 19:42:33 +0000 Subject: should give better performance if we search for what we want instead of using a string match --- FS/FS/cust_pkg_reason.pm | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/FS/FS/cust_pkg_reason.pm b/FS/FS/cust_pkg_reason.pm index 403751369..bb0542be2 100644 --- a/FS/FS/cust_pkg_reason.pm +++ b/FS/FS/cust_pkg_reason.pm @@ -136,12 +136,15 @@ sub reasontext { use FS::h_cust_pkg; use FS::h_cust_pkg_reason; +use FS::Schema qw(dbdef); sub _upgrade_data { # class method my ($class, %opts) = @_; - my $test_cust_pkg_reason = new FS::cust_pkg_reason; - return '' unless $test_cust_pkg_reason->dbdef_table->column('action'); + return '' unless dbdef->table('cust_pkg_reason')->column('action'); + + my $action_replace = + " AND ( history_action = 'replace_old' OR history_action = 'replace_new' )"; my $count = 0; my @unmigrated = qsearch('cust_pkg_reason', { 'action' => '' } ); @@ -151,27 +154,24 @@ sub _upgrade_data { # class method next unless scalar(@history_cust_pkg_reason) == 1; - my %action_value = ( op => 'LIKE', - value => 'replace_%', - ); my $hashref = { pkgnum => $_->pkgnum, history_date => $history_cust_pkg_reason[0]->history_date, - history_action => { %action_value }, }; - my @history = qsearch({ table => 'h_cust_pkg', - hashref => $hashref, - order_by => 'ORDER BY history_action', + my @history = qsearch({ table => 'h_cust_pkg', + hashref => $hashref, + extra_sql => $action_replace, + order_by => 'ORDER BY history_action', }); my $fuzz = 0; while (scalar(@history) < 2 && $fuzz < 3) { $hashref->{history_date}++; - $hashref->{history_action} = { %action_value }; # qsearch distorts this! $fuzz++; - push @history, qsearch({ table => 'h_cust_pkg', - hashref => $hashref, - order_by => 'ORDER BY history_action', + push @history, qsearch({ table => 'h_cust_pkg', + hashref => $hashref, + extra_sql => $action_replace, + order_by => 'ORDER BY history_action', }); } @@ -226,26 +226,23 @@ sub _upgrade_data { # class method }); foreach ( @unmigrated ) { - my %action_value = ( op => 'LIKE', - value => 'replace_%', - ); my $hashref = { pkgnum => $_->pkgnum, history_date => $_->date, - history_action => { %action_value }, }; - my @history = qsearch({ table => 'h_cust_pkg', - hashref => $hashref, - order_by => 'ORDER BY history_action', + my @history = qsearch({ table => 'h_cust_pkg', + hashref => $hashref, + extra_sql => $action_replace, + order_by => 'ORDER BY history_action', }); my $fuzz = 0; while (scalar(@history) < 2 && $fuzz < 3) { $hashref->{history_date}++; - $hashref->{history_action} = { %action_value }; # qsearch distorts this! $fuzz++; push @history, qsearch({ table => 'h_cust_pkg', hashref => $hashref, + extra_sql => $action_replace, order_by => 'ORDER BY history_action', }); } -- cgit v1.2.1 From 1c4c7cf9e2c1b4baae0453d844e23391cda7dfbb Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Mar 2009 22:33:09 +0000 Subject: don't throw 'Use of uninitialized value in addition (+) at /usr/local/share/perl/5.8.8/FS/cust_svc.pm line 626.' error when using attribute_since_sqlradacct --- 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 30b23908c..320f78aa0 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -629,7 +629,8 @@ sub attribute_since_sqlradacct { ) or die $dbh->errstr; $sth->execute($username, $start, $end) or die $sth->errstr; - $sum += $sth->fetchrow_arrayref->[0]; + my $row = $sth->fetchrow_arrayref; + $sum += $row->[0] if defined($row->[0]); warn "$mes done SUMing sessions\n" if $DEBUG; -- cgit v1.2.1 From 29c1d4f0ed46a2ff02353fdc6c0caf3553462f6e Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 15 Mar 2009 22:44:17 +0000 Subject: adding quick usage resetting tool --- bin/svc_acct-recalculate_usage | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 bin/svc_acct-recalculate_usage diff --git a/bin/svc_acct-recalculate_usage b/bin/svc_acct-recalculate_usage new file mode 100644 index 000000000..1b3955b21 --- /dev/null +++ b/bin/svc_acct-recalculate_usage @@ -0,0 +1,110 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw($opt_s $opt_u $opt_p $opt_k); +use Getopt::Std; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch qsearchs); +use FS::svc_acct; +use FS::cust_svc; + +my %field2sub = ( + 'seconds' => sub { + my($svc_acct, $cust_pkg) = @_; + $svc_acct->seconds_since_sqlradacct( $cust_pkg->last_bill, time ); + }, + 'upbytes' => sub { + my($svc_acct, $cust_pkg) = @_; + $svc_acct->attribute_since_sqlradacct( + $cust_pkg->last_bill, time, 'AcctInputOctets' ); + }, + 'downbytes' => sub { + my($svc_acct, $cust_pkg) = @_; + $svc_acct->attribute_since_sqlradacct( + $cust_pkg->last_bill, time, 'AcctOutputOctets' ); + }, + 'totalbytes' => sub { + my($svc_acct, $cust_pkg) = @_; + $svc_acct->attribute_since_sqlradacct( + $cust_pkg->last_bill, time, 'AcctInputOctets' ) + + + $svc_acct->attribute_since_sqlradacct( + $cust_pkg->last_bill, time, 'AcctOutputOctets' ) + ; + }, +); + +my $user = shift or die &usage; +adminsuidsetup $user; + +my $field = shift; +die "can only reset seconds, upbytes, downbytes or totalbytes" + unless $field2sub{$field}; + +my $value = shift; + +#false laziness w/freeside-reexport +getopts('s:u:p:k:'); + +my @svc_x = (); +if ( $opt_s ) { + my $cust_svc = qsearchs('cust_svc', { svcnum=>$opt_s } ) + or die "svcnum $opt_s not found\n"; + push @svc_x, $cust_svc->svc_x; +} elsif ( $opt_u ) { + my $svc_x = qsearchs('svc_acct', { username=>$opt_u } ) + or die "username $opt_u not found\n"; + push @svc_x, $svc_x; +} elsif ( $opt_p ) { + push @svc_x, map { $_->svc_x } qsearch('cust_svc', { svcpart=>$opt_p } ); + die "no services with svcpart $opt_p found\n" unless @svc_x; +} elsif ( $opt_k ) { + push @svc_x, + map { $_->svc_x } + qsearch({ + table => 'cust_svc', + addl_from => 'LEFT JOIN cust_pkg USING ( pkgnum )', + extra_sql => "WHERE pkgpart = $opt_k", + }); + die "no services with pkgpart $opt_k found\n" unless @svc_x; +} + +warn "setting $field to $value before usage\n"; +foreach my $svc_x ( @svc_x ) { + my $cust_pkg = $svc_x->cust_svc->cust_pkg; + my $cust_usage = $value - &{ $field2sub{$field} }( $svc_x, $cust_pkg ); +# warn "resetting ". $svc_x->svcnum.':'.$svc_x->username. " to $cust_usage\n"; + warn "$field for ". $svc_x->svcnum.':'.$svc_x->username. " reached limit\n" + if $cust_usage <= 0; + $svc_x->$field($cust_usage); + + my $error = $svc_x->replace; + die $error if $error; +} + +sub usage { + die "Usage:\n\n svc_acct-recalculate_usage user [ -s svcnum | -u username | -p svcpart ]\n"; +} + +=head1 NAME + +svc-acct-recalculate_usage - Command line tool to recalculate usage for existing services + +=head1 SYNOPSIS + + svc_acct-recalculate_usage user usagefield initialvalue [ -s svcnum | -u username | -p svcpart ] + + #recalculate a 1gb totalbytes limit for pkgpart 2 + svc_acct-recalculate_usage ivan totalbytes 1073741824 -k 2 + +=head1 DESCRIPTION + +Re-calculates the specified usage field for the specified service(s) (selected +by svcnum, username or svcpart). + +=head1 SEE ALSO + +L, L, L + +=cut + -- cgit v1.2.1 From 8d419aa7155fd8edd1f2f2338265ec372a8eea5d Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Mar 2009 00:57:59 +0000 Subject: comment change --- FS/FS/svc_broadband.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm index eb2964635..d4d41018a 100755 --- a/FS/FS/svc_broadband.pm +++ b/FS/FS/svc_broadband.pm @@ -217,7 +217,7 @@ sub check { ; return $error if $error; - #redundant, but prevents further problems until column constraint in place + #redundant, but better error message return "MAC already in use" if scalar( qsearch( 'svc_broadband', { 'mac_addr', $self->mac_addr } ) ); -- cgit v1.2.1 From 7f37738733c36b6af0f421779addac3e9af9a809 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Mar 2009 04:22:42 +0000 Subject: use part_svc_router --- FS/FS/svc_broadband.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm index d4d41018a..d9a25b487 100755 --- a/FS/FS/svc_broadband.pm +++ b/FS/FS/svc_broadband.pm @@ -6,6 +6,7 @@ use FS::Record qw( qsearchs qsearch dbh ); use FS::svc_Common; use FS::cust_svc; use FS::addr_block; +use FS::part_svc_router; use NetAddr::IP; @ISA = qw( FS::svc_Common ); -- cgit v1.2.1 From b6971314b234feb121153158fc05eb0f8865ba74 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Mar 2009 05:54:34 +0000 Subject: fix custnum display on domain view --- httemplate/view/svc_domain.cgi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httemplate/view/svc_domain.cgi b/httemplate/view/svc_domain.cgi index 8c1f4cecd..36577d39c 100755 --- a/httemplate/view/svc_domain.cgi +++ b/httemplate/view/svc_domain.cgi @@ -138,9 +138,9 @@ my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum}); my $pkgnum = $cust_svc->getfield('pkgnum'); my($cust_pkg, $custnum, $display_custnum); if ($pkgnum) { - $cust_pkg =qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + $cust_pkg = qsearchs('cust_pkg', {'pkgnum'=>$pkgnum} ); $custnum = $cust_pkg->custnum; - $custnum = $cust_pkg->cust_main->display_custnum; + $display_custnum = $cust_pkg->cust_main->display_custnum; } else { $cust_pkg = ''; $custnum = ''; -- cgit v1.2.1 From 6724da406d1fdef94396ff0b8b7566ae83695914 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Mar 2009 06:22:45 +0000 Subject: 5.10! welcome to the future --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8df079cfb..59d249837 100644 --- a/Makefile +++ b/Makefile @@ -121,7 +121,7 @@ RT_PATH = /opt/rt3 #only used for dev kludge now, not a big deal FREESIDE_PATH = `pwd` -PERL_INC_DEV_KLUDGE = /usr/local/share/perl/5.8.8/ +PERL_INC_DEV_KLUDGE = /usr/local/share/perl/5.10.0/ VERSION=1.9.0cvs TAG=freeside_1_9_0 -- cgit v1.2.1 From 36f9f3a83dcdac4010fc039274a5e19edb5df30b Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Mar 2009 07:13:10 +0000 Subject: eliminate black diamond arrows on iso-8859-1 chars in Locale::SubCountry states, RT#4997 --- htetc/freeside-base1.99.conf | 3 +++ htetc/freeside-base1.conf | 3 +++ htetc/freeside-base2.conf | 3 +++ 3 files changed, 9 insertions(+) diff --git a/htetc/freeside-base1.99.conf b/htetc/freeside-base1.99.conf index 8e890e646..ce3c3f240 100644 --- a/htetc/freeside-base1.99.conf +++ b/htetc/freeside-base1.99.conf @@ -8,6 +8,9 @@ PerlModule HTML::Mason::ApacheHandler PerlRequire "%%%MASON_HANDLER%%%" +#Locale::SubCountry +AddDefaultCharset ISO-8859-1 + AuthName Freeside AuthType Basic diff --git a/htetc/freeside-base1.conf b/htetc/freeside-base1.conf index 73962a721..7b8d9da68 100644 --- a/htetc/freeside-base1.conf +++ b/htetc/freeside-base1.conf @@ -2,6 +2,9 @@ PerlModule HTML::Mason +#Locale::SubCountry +AddDefaultCharset ISO-8859-1 + AuthName Freeside AuthType Basic diff --git a/htetc/freeside-base2.conf b/htetc/freeside-base2.conf index 6606129d9..1cd1cc550 100644 --- a/htetc/freeside-base2.conf +++ b/htetc/freeside-base2.conf @@ -8,6 +8,9 @@ PerlModule HTML::Mason::ApacheHandler PerlRequire "%%%MASON_HANDLER%%%" +#Locale::SubCountry +AddDefaultCharset ISO-8859-1 + AuthName Freeside AuthType Basic -- cgit v1.2.1 From 26119738eaf2b519d91c855c23986f873303887f Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Mar 2009 07:14:29 +0000 Subject: allow country selection on credit card entry, RT#4997 --- httemplate/elements/location.html | 19 ++++++------ httemplate/misc/payment.cgi | 59 ++++++++----------------------------- httemplate/misc/process/payment.cgi | 2 +- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/httemplate/elements/location.html b/httemplate/elements/location.html index d7b73a220..6691bc84e 100644 --- a/httemplate/elements/location.html +++ b/httemplate/elements/location.html @@ -3,20 +3,21 @@ Example: include( '/elements/location.html', - 'object' => $cust_main, # or $cust_location - 'prefix' => $pre, #only for cust_main objects - 'onchange' => $javascript, - 'disabled' => $disabled, - 'same_checked' => $same_checked, - 'geocode' => $geocode, #passed through - 'no_asterisks' => 0, #set true to disable the red asterisks next - #to required fields + 'object' => $cust_main, # or $cust_location + 'prefix' => $pre, #only for cust_main objects + 'onchange' => $javascript, + 'disabled' => $disabled, + 'same_checked' => $same_checked, + 'geocode' => $geocode, #passed through + 'no_asterisks' => 0, #set true to disable the red asterisks next + #to required fields + 'address1_label' => 'Address', #label for address ) - <%$r%>Address + <%$r%><% $opt{'address1_label'} || 'Address' %> - Payment amount + Payment amount - - + -% my %part_pkg = (); +% local($FS::cust_pkg::DEBUG) = 2; % foreach my $cust_pkg (@$packages) { % % if ( $bgcolor eq $bgcolor1 ) { @@ -85,18 +85,15 @@ Current packages % $bgcolor = $bgcolor1; % } % -% $part_pkg{$cust_pkg->pkgpart} ||= $cust_pkg->part_pkg; -% $cust_pkg->{'_pkgpart'} ||= $part_pkg{$cust_pkg->pkgpart}; #XXX cache kludge +% $cust_pkg->{'_pkgpart'} = new FS::part_pkg { $cust_pkg->hash }; #quelle klud % % my %iopt = ( % 'bgcolor' => $bgcolor, % 'cust_pkg' => $cust_pkg, -% 'part_pkg' => $part_pkg{$cust_pkg->pkgpart}, +% 'part_pkg' => $cust_pkg->part_pkg, % %conf_opt, % ); % -% my $oldDEBUG = $FS::cust_pkg::DEBUG; -% $FS::cust_pkg::DEBUG = 2; @@ -108,8 +105,6 @@ Current packages <% include('packages/services.html', %iopt) %> -% $FS::cust_pkg::DEBUG = $oldDEBUG; - % }
$"> @@ -24,11 +24,6 @@ % % my( $payinfo, $paycvv, $month, $year ) = ( '', '', '', '' ); % my $payname = $cust_main->first. ' '. $cust_main->getfield('last'); -% my $address1 = $cust_main->address1; -% my $address2 = $cust_main->address2; -% my $city = $cust_main->city; -% my $state = $cust_main->state; -% my $zip = $cust_main->zip; % if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) { % $payinfo = $cust_main->paymask; % $paycvv = $cust_main->paycvv; @@ -37,13 +32,13 @@ % }
Card number + Card number - + - + - + - - - - - - - - - + <% include( '/elements/location.html', + 'object' => $cust_main, #XXX errors??? + 'no_asterisks' => 1, + 'address1_label' => 'Card billing address', + ) + %> + % } elsif ( $payby eq 'CHEK' ) { % % my( $payinfo1, $payinfo2, $payname, $ss, $paytype, $paystate, diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi index 2baca1e39..ea0c7946d 100644 --- a/httemplate/misc/process/payment.cgi +++ b/httemplate/misc/process/payment.cgi @@ -44,7 +44,7 @@ $cgi->param('payby') =~ /^(CARD|CHEK)$/ or errorpage("illegal payby ". $cgi->param('payby')); my $payby = $1; my %payby2fields = ( - 'CARD' => [ qw( address1 address2 city state zip ) ], + 'CARD' => [ qw( address1 address2 city county state zip country ) ], 'CHEK' => [ qw( ss paytype paystate stateid stateid_state ) ], ); my %type = ( 'CARD' => 'credit card', -- cgit v1.2.1 From 59a12152b6521065b8a2a82a48575445b6cd61d8 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Mar 2009 08:08:44 +0000 Subject: get the dup checking right --- FS/FS/svc_broadband.pm | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm index d9a25b487..6007c7083 100755 --- a/FS/FS/svc_broadband.pm +++ b/FS/FS/svc_broadband.pm @@ -111,6 +111,8 @@ sub table_info { sub table { 'svc_broadband'; } +sub table_dupcheck_fields { ( 'mac_addr' ); } + =item search_sql STRING Class method which returns an SQL fragment to search for the given string. @@ -218,10 +220,6 @@ sub check { ; return $error if $error; - #redundant, but better error message - return "MAC already in use" - if scalar( qsearch( 'svc_broadband', { 'mac_addr', $self->mac_addr } ) ); - if($self->speed_up < 0) { return 'speed_up must be positive'; } if($self->speed_down < 0) { return 'speed_down must be positive'; } @@ -293,6 +291,18 @@ sub check { $self->SUPER::check; } +sub _check_duplicate { + my $self = shift; + + return "MAC already in use" + if ( $self->mac_addr && + scalar( qsearch( 'svc_broadband', { 'mac_addr', $self->mac_addr } ) ) + ); + + ''; +} + + =item NetAddr Returns a NetAddr::IP object containing the IP address of this service. The netmask -- cgit v1.2.1 From 72d61f5de9e35ec0a01b62eff696ebbbb830846c Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Mar 2009 15:52:17 +0000 Subject: a tool for migrating package elements to services --- bin/make-pkg-fruit | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100755 bin/make-pkg-fruit diff --git a/bin/make-pkg-fruit b/bin/make-pkg-fruit new file mode 100755 index 000000000..61d707f4a --- /dev/null +++ b/bin/make-pkg-fruit @@ -0,0 +1,172 @@ +#!/usr/bin/perl -w + +use strict; +use FS::UID qw( adminsuidsetup ); +use FS::Record qw( qsearch qsearchs ); +use FS::part_export; +use FS::export_svc; +use FS::pkg_svc; +use FS::part_svc; +use FS::part_pkg; +use FS::cust_svc; +use FS::svc_Common; +use FS::svc_broadband; +use FS::part_svc_router; + +my $exporttype = 'prizm'; +my $pkg_property = 'pkg'; +my $svc_property = 'performance_profile'; + +my $user = shift or die &usage; + +$FS::svc_Common::noexport_hack = 1; +$FS::cust_svc::ignore_quantity = 1; +$FS::UID::AutoCommit = 0; + +my $DEBUG = 0; + +my $dbh = adminsuidsetup($user); + +my @exportnum = map { $_->exportnum } + qsearch( 'part_export', { 'exporttype' => $exporttype } ); + +die "no $exporttype exports found\n" unless scalar(@exportnum); + +my %pkg_svc_map = (); + +my @old_svcpart = (); +push @old_svcpart, map { $_->svcpart } + qsearch ( 'export_svc', { 'exportnum' => $_ } ) + foreach @exportnum; + +die "no svcparts found\n" unless scalar(@old_svcpart); + +foreach (@old_svcpart) { + foreach my $pkg_svc ( qsearch( 'pkg_svc', + { 'svcpart' => $_, + 'quantity' => { 'op' => '>', + 'value' => '0', + }, + } + ) + ) + { + warn "updating package ". $pkg_svc->pkgpart. "\n" if $DEBUG; + my $pkg_from = $pkg_svc->part_pkg->$pkg_property; + unless ( $pkg_svc_map{ $pkg_from }{ $pkg_svc->svcpart } ) { + my $old_part_svc = $pkg_svc->part_svc; + my $part_svc = new FS::part_svc( { $old_part_svc->hash } ); + $part_svc->svcpart(''); + + my $svcdb = $part_svc->svcdb; + foreach ( $old_part_svc->all_part_svc_column ) { + my $formatter = FS::part_svc->svc_table_fields($svcdb)->{$_}->{format} + || sub { shift }; + + $part_svc->setfield( $svcdb.'__'.$_->columnname.'_flag', $_->columnflag); + $part_svc->setfield( $svcdb.'__'.$_->columnname, + &$formatter($_->columnvalue) + ); + } + + my $formatter = + FS::part_svc->svc_table_fields($svcdb)->{$svc_property}->{format} + || sub { shift }; + $part_svc->setfield( $svcdb.'__'.$svc_property.'_flag', 'F'); + $part_svc->setfield( $svcdb.'__'.$svc_property, + &$formatter($pkg_svc->part_pkg->$pkg_property) + ); + my $error = $part_svc->insert( [], + { map { $_->exportnum => 1 } + $old_part_svc->part_export + }, + ); + die "error inserting service: $error\n" if $error; + + # this part is specific to svc_broadband + foreach (qsearch( 'part_svc_router', { 'svcpart' => $pkg_svc->svcpart } )) + { + my $part_svc_router = new FS::part_svc_router( { $_->hash } ); + $part_svc_router->svcrouternum( '' ); + $part_svc_router->svcpart( $part_svc->svcpart ); + my $error = $part_svc_router->insert; + die "error associating service with router: $error\n" if $error; + } + + $pkg_svc_map{ $pkg_from }{ $pkg_svc->svcpart } = $part_svc->svcpart; + + } + + my $new_pkg_svc = new FS::pkg_svc( { $pkg_svc->hash } ); + $new_pkg_svc->svcpart( $pkg_svc_map{ $pkg_from }{ $pkg_svc->svcpart } ); + my $error = $pkg_svc->delete; + die "error removing old service from package: $error\n" if $error; + $error = $new_pkg_svc->insert; + die "error adding new service to package: $error\n" if $error; + + } +} +warn "done with packages\n" if $DEBUG; + +foreach my $svcpart ( @old_svcpart ) { + foreach my $cust_svc ( qsearch( 'cust_svc', { 'svcpart' => $svcpart } ) ) { + my $svc_x = $cust_svc->svc_x; + my $cust_pkg = $cust_svc->cust_pkg; + die "can't handle unattached service ". $cust_svc->svcnum unless $cust_pkg; + my $pkg_from = $cust_pkg->part_pkg->$pkg_property; + $svc_x->setfield( $svc_property, $pkg_from ); + $svc_x->setfield( 'svcpart', $pkg_svc_map{ $pkg_from }{ $svcpart } ); + my $error = $svc_x->replace; + die "error replacing service ". $svc_x->svcnum. ": $error\n" if $error; + + $cust_svc->svcpart( $pkg_svc_map{ $pkg_from }{ $svcpart } ); + $error = $cust_svc->replace; + die "error replacing customer service ". $cust_svc->svcnum. ": $error\n" + if $error; + } + + my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $svcpart } ); + die "can't find old part_svc!" unless $part_svc; + + my $new_part_svc = new FS::part_svc( { $part_svc->hash } ); + $new_part_svc->disabled('Y'); + my $svcdb = $part_svc->svcdb; + foreach ( $part_svc->all_part_svc_column ) { + my $formatter = FS::part_svc->svc_table_fields($svcdb)->{$_}->{format} + || sub { shift }; + + $part_svc->setfield( $svcdb.'__'.$_->columnname.'_flag', $_->columnflag); + $part_svc->setfield( $svcdb.'__'.$_->columnname, + &$formatter($_->columnvalue) + ); + } + my $error = $new_part_svc->replace($part_svc, '1.3-COMPAT'); + die "error disabling service: $error\n" if $error; +} + +$dbh->commit or die $dbh->errstr; +$dbh->disconnect or die $dbh->errstr; + + +sub usage { + die "Usage:\n\n make-pkg-fruit user\n"; +} + +=head1 NAME + +make-pkg-fruit - Tool to migrate package properties to services + +=head1 SYNOPSIS + + make-pkg-fruit + +=head1 DESCRIPTION + +Multiplies out services with package properties and migrates package +definitions and customer services to the new services. Read the source. + +=head1 SEE ALSO + +=cut + +1; -- cgit v1.2.1 From d3784b40552e9f00c9d803ac0833e09828c73d96 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Mar 2009 17:06:40 +0000 Subject: have prizm use service data rather than package data to select a profile RT#4853 --- FS/FS/Schema.pm | 1 + FS/FS/part_export/prizm.pm | 12 +++++++++--- httemplate/edit/svc_broadband.cgi | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 65f7a7f40..4ffeaa2e8 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1666,6 +1666,7 @@ sub tables_hashref { 'longitude', 'decimal', 'NULL', '', '', '', 'altitude', 'decimal', 'NULL', '', '', '', 'vlan_profile', 'varchar', 'NULL', $char_d, '', '', + 'performance_profile', 'varchar', 'NULL', $char_d, '', '', ], 'primary_key' => 'svcnum', 'unique' => [ [ 'mac_addr' ] ], diff --git a/FS/FS/part_export/prizm.pm b/FS/FS/part_export/prizm.pm index 2d4d8584c..97054408f 100644 --- a/FS/FS/part_export/prizm.pm +++ b/FS/FS/part_export/prizm.pm @@ -200,6 +200,9 @@ sub _export_insert { # } # } + my $performance_profile = $svc->performance_profile; + $performance_profile ||= $svc->cust_svc->cust_pkg->part_pkg->pkg; + my $element_name_length = 50; $element_name_length = $1 if $self->option('element_name_length') =~ /^\s*(\d+)\s*$/; @@ -211,7 +214,7 @@ sub _export_insert { $location, $contact, sprintf("%032X", $svc->authkey), - $svc->cust_svc->cust_pkg->part_pkg->pkg, + $performance_profile, $svc->vlan_profile, ($self->option('ems') ? 1 : 0 ), ); @@ -256,7 +259,7 @@ sub _export_insert { $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfigSet', [ $element ], - $svc->cust_svc->cust_pkg->part_pkg->pkg, + $performance_profile, 0, 1, ); @@ -395,9 +398,12 @@ sub _export_replace { return $err_or_som unless ref($err_or_som); + my $performance_profile = $new->performance_profile; + $performance_profile ||= $new->cust_svc->cust_pkg->part_pkg->pkg; + $err_or_som = $self->prizm_command('NetworkIfService', 'setElementConfigSet', [ $element ], - $new->cust_svc->cust_pkg->part_pkg->pkg, + $performance_profile, 0, 1, ); diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi index e60c76c90..01e58cdc4 100644 --- a/httemplate/edit/svc_broadband.cgi +++ b/httemplate/edit/svc_broadband.cgi @@ -14,6 +14,7 @@ 'longitude' => 'Longitude', 'altitude' => 'Altitude', 'vlan_profile' => 'VLAN profile', + 'performance_profile' => 'Performance profile', 'authkey' => 'Authentication key', }, 'fields' => \@fields, @@ -34,7 +35,7 @@ my $conf = new FS::Conf; my @fields = ( qw( description ip_addr speed_down speed_up blocknum ), { field=>'block_label', type=>'fixed' }, - qw( mac_addr latitude longitude altitude vlan_profile authkey ) + qw( mac_addr latitude longitude altitude vlan_profile performance_profile authkey ) ); my $fixedblock = ''; -- cgit v1.2.1 From 541207eb5505eee6eafd25e861230bdb36ac5fb3 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Mar 2009 23:28:28 +0000 Subject: avoid the need for approximate comparisons RT#4903 --- FS/FS/Schema.pm | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 4ffeaa2e8..7307165da 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -320,6 +320,8 @@ sub tables_hashref { my @perl_type = ( 'text', 'NULL', '' ); my @money_type = ( 'decimal', '', '10,2' ); my @money_typen = ( 'decimal', 'NULL', '10,2' ); + my @taxrate_type = ( 'decimal', '', '14,8' ); # requires pg 8 for + my @taxrate_typen = ( 'decimal', 'NULL', '14,8' ); # fs-upgrade to work my $username_len = 32; #usernamemax config file @@ -770,17 +772,17 @@ sub tables_hashref { 'location', 'varchar', 'NULL', $char_d, '', '',#provided by tax authority 'taxclassnum', 'int', '', '', '', '', 'effective_date', @date_type, '', '', - 'tax', 'real', '', '', '', '', # tax % - 'excessrate', 'real', 'NULL','', '', '', # second tax % + 'tax', @taxrate_type, '', '', # tax % + 'excessrate', @taxrate_typen, '', '', # second tax % 'taxbase', @money_typen, '', '', # amount at first tax rate 'taxmax', @money_typen, '', '', # maximum about at both rates - 'usetax', 'real', 'NULL', '', '', '', # tax % when non-local - 'useexcessrate', 'real', 'NULL', '', '', '', # second tax % when non-local + 'usetax', @taxrate_typen, '', '', # tax % when non-local + 'useexcessrate', @taxrate_typen, '', '', # second tax % when non-local 'unittype', 'int', 'NULL', '', '', '', # for fee - 'fee', 'real', 'NULL', '', '', '', # amount tax per unit - 'excessfee', 'real', 'NULL', '', '', '', # second amount tax per unit - 'feebase', 'real', 'NULL', '', '', '', # units taxed at first rate - 'feemax', 'real', 'NULL', '', '', '', # maximum number of unit taxed + 'fee', @taxrate_typen, '', '', # amount tax per unit + 'excessfee', @taxrate_typen, '', '', # second amount tax per unit + 'feebase', @taxrate_typen, '', '', # units taxed at first rate + 'feemax', @taxrate_typen, '', '', # maximum number of unit taxed 'maxtype', 'int', 'NULL', '', '', '', # indicator of how thresholds accumulate 'taxname', 'varchar', 'NULL', $char_d, '', '', # may appear on invoice 'taxauth', 'int', 'NULL', '', '', '', # tax authority -- cgit v1.2.1 From 2755d4a4810600f4392eaf73f362b4f358adeec6 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 09:58:17 +0000 Subject: add eps preview to config, for RT#5025 --- FS/FS/Conf.pm | 2 +- FS/FS/Mason.pm | 1 + FS/FS/Misc/eps2png.pm | 278 +++++++++++++++++++++++++++++++++++++ httemplate/config/config-image.cgi | 5 +- httemplate/config/config-view.cgi | 32 +++-- httemplate/docs/credits.html | 11 +- httemplate/docs/license.html | 4 + 7 files changed, 317 insertions(+), 16 deletions(-) create mode 100644 FS/FS/Misc/eps2png.pm diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 3f150e1e7..8ea57304c 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2304,7 +2304,7 @@ worry that config_items is freeside-specific and icky. 'key' => 'logo.eps', 'section' => 'billing', #? 'description' => 'Company logo for printed and PDF invoices, in EPS format.', - 'type' => 'binary', + 'type' => 'image', 'per_agent' => 1, #XXX as above, kinda }, diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index ee777a485..bcdc2fe8e 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -91,6 +91,7 @@ Initializes the Mason environment, loads all Freeside and RT libraries, etc. use FS::UI::bytecount; use FS::Msgcat qw(gettext geterror); use FS::Misc qw( send_email send_fax states_hash counties state_label ); + use FS::Misc::eps2png qw( eps2png ); use FS::Report::Table::Monthly; use FS::TicketSystem; use FS::Tron qw( tron_lint ); diff --git a/FS/FS/Misc/eps2png.pm b/FS/FS/Misc/eps2png.pm new file mode 100644 index 000000000..49c1d5682 --- /dev/null +++ b/FS/FS/Misc/eps2png.pm @@ -0,0 +1,278 @@ +package FS::Misc::eps2png; + +#based on eps2png by Johan Vromans +#Copyright 1994,2008 by Johan Vromans. +#This program is free software; you can redistribute it and/or +#modify it under the terms of the Perl Artistic License or the +#GNU General Public License as published by the Free Software +#Foundation; either version 2 of the License, or (at your option) any +#later version. + +use strict; +use vars qw( @ISA @EXPORT_OK ); +use Exporter; +use File::Temp; +use File::Slurp qw( slurp ); +#use FS::UID; + +@ISA = qw( Exporter ); +@EXPORT_OK = qw( eps2png ); + +################ Program parameters ################ + +# Some GhostScript programs can produce GIF directly. +# If not, we need the PBM package for the conversion. +# NOTE: This will be changed upon install. +my $use_pbm = 0; + +my $res = 82; # default resolution +my $scale = 1; # default scaling +my $mono = 0; # produce BW images if non-zero +my $format; # output format +my $gs_format; # GS output type +my $output; # output, defaults to STDOUT +my $antialias = 8; #4; # antialiasing +my $DEF_width; # desired widht +my $DEF_height; # desired height +#my $DEF_width = 90; # desired widht +#my $DEF_height = 36; # desired height + +my ($verbose,$trace,$test,$debug) = (0,0,0,1); +#handle_options (); +set_out_type ('png'); # unless defined $format; +warn "Producing $format ($gs_format) image.\n" if $verbose; + +$trace |= $test | $debug; +$verbose |= $trace; + +################ Presets ################ + +################ The Process ################ + +my $err = 0; + +sub eps2png { + my( $eps, %options ) = @_; #well, no options yet + + my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc; + my $eps_file = new File::Temp( TEMPLATE => 'image.XXXXXXXX', + DIR => $dir, + SUFFIX => '.eps', + #UNLINK => 0, + ) or die "can't open temp file: $!\n"; + print $eps_file $eps; + close $eps_file; + + my @eps = split(/\r?\n/, $eps); + + warn "converting eps (". length($eps). " bytes, ". scalar(@eps). " lines)\n" + ;#if $verbose; + + my $line = shift @eps; #; + unless ( $eps =~ /^%!PS-Adobe.*EPSF-/ ) { + warn "not EPS file (no %!PS-Adobe header)\n"; + return; #empty png file? + } + + my $ps = ""; # PostScript input data + my $xscale; + my $yscale; + my $gotbb; + + # Prevent derived values from propagating. + my $width = $DEF_width; + my $height = $DEF_height; + + while ( @eps ) { + + $line = shift(@eps)."\n"; + + # Search for BoundingBox. + if ( $line =~ /^%%BoundingBox:\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/i ) { + $gotbb++; + warn "$eps_file: x0=$1, y0=$2, w=", $3-$1, ", h=", $4-$2 + if $verbose; + + if ( defined $width ) { + $res = 72; + $xscale = $width / ($3 - $1); + if ( defined $height ) { + $yscale = $height / ($4 - $2); + } + else { + $yscale = $xscale; + $height = ($4 - $2) * $yscale; + } + } + elsif ( defined $height ) { + $res = 72; + $yscale = $height / ($4 - $2); + if ( defined $width ) { + $xscale = $width / ($3 - $1); + } + else { + $xscale = $yscale; + $width = ($3 - $1) * $xscale; + } + } + unless ( defined $xscale ) { + $xscale = $yscale = $scale; + # Calculate actual width. + $width = $3 - $1; + $height = $4 - $2; + # Normal PostScript resolution is 72. + $width *= $res/72 * $xscale; + $height *= $res/72 * $yscale; + # Round up. + $width = int ($width + 0.5) + 1; + $height = int ($height + 0.5) + 1; + } + warn ", width=$width, height=$height\n" if $verbose; + + # Scale. + $ps .= "$xscale $yscale scale\n" + if $xscale != 1 || $yscale != 1; + + # Create PostScript code to translate coordinates. + $ps .= (0-$1) . " " . (0-$2) . " translate\n" + unless $1 == 0 && $2 == 0; + + # Include the image, show and quit. + $ps .= "($eps_file) run\n". + "showpage\n". + "quit\n"; + + last; + } + elsif ( $line =~ /^%%EndComments/i ) { + last; + } + } + + unless ( $gotbb ) { + warn "No bounding box in $eps_file\n"; + return; + } + + #it would be better to ask gs to spit out files on stdout, but c'est la vie + + #my $out_file; # output file + #my $pbm_file; # temporary file for PBM conversion + + my $out_file = new File::Temp( TEMPLATE => 'image.XXXXXXXX', + DIR => $dir, + SUFFIX => '.png', + #UNLINK => 0, + ) or die "can't open temp file: $!\n"; + + my $pbm_file = new File::Temp( TEMPLATE => 'image.XXXXXXXX', + DIR => $dir, + SUFFIX => '.pbm', + #UNLINK => 0, + ) or die "can't open temp file: $!\n"; + + # Note the temporary PBM file is created where the output file is + # located, since that will guarantee accessibility (and a valid + # filename). + warn "Creating $out_file\n" if $verbose; + + my $gs0 = "gs -q -dNOPAUSE -r$res -g${width}x$height"; + my $gs1 = "-"; + $gs0 .= " -dTextAlphaBits=$antialias -dGraphicsAlphaBits=$antialias" + if $antialias; + if ( $format eq 'png' ) { + mysystem ("$gs0 -sDEVICE=". ($mono ? "pngmono" : $gs_format). + " -sOutputFile=$out_file $gs1", $ps); + } + elsif ( $format eq 'jpg' ) { + mysystem ("$gs0 -sDEVICE=". ($mono ? "jpeggray" : $gs_format). + " -sOutputFile=$out_file $gs1", $ps); + } + elsif ( $format eq 'gif' ) { + if ( $use_pbm ) { + # Convert to PPM and use some of the PBM converters. + mysystem ("$gs0 -sDEVICE=". ($mono ? "pbm" : "ppm"). + " -sOutputFile=$pbm_file $gs1", $ps); + # mysystem ("pnmcrop $pbm_file | ppmtogif > $out_file"); + mysystem ("ppmtogif $pbm_file > $out_file"); + unlink ($pbm_file); + } + else { + # GhostScript has GIF drivers built-in. + mysystem ("$gs0 -sDEVICE=". ($mono ? "gifmono" : "gif8"). + " -sOutputFile=$out_file $gs1", $ps); + } + } + else { + warn "ASSERT ERROR: Unhandled output type: $format\n"; + exit (1); + } + +# unless ( -s $out_file ) { +# warn "Problem creating $out_file for $eps_file\n"; +# $err++; +# } + + slurp($out_file); + +} + +exit 1 if $err; + +################ Subroutines ################ + +sub mysystem { + my ($cmd, $data) = @_; + warn "+ $cmd\n" if $trace; + if ( $data ) { + if ( $trace ) { + my $dp = ">> " . $data; + $dp =~ s/\n(.)/\n>> $1/g; + warn "$dp"; + } + open (CMD, "|$cmd") or die ("$cmd: $!\n"); + print CMD $data; + close CMD or die ("$cmd close: $!\n"); + } + else { + system ($cmd); + } +} + +sub set_out_type { + my ($opt) = lc (shift (@_)); + if ( $opt =~ /^png(mono|gray|16|256|16m|alpha)?$/ ) { + $format = 'png'; + $gs_format = $format.(defined $1 ? $1 : '16m'); + } + elsif ( $opt =~ /^gif(mono)?$/ ) { + $format = 'gif'; + $gs_format = $format.(defined $1 ? $1 : ''); + } + elsif ( $opt =~ /^(jpg|jpeg)(gray)?$/ ) { + $format = 'jpg'; + $gs_format = 'jpeg'.(defined $2 ? $2 : ''); + } + else { + warn "ASSERT ERROR: Invalid value to set_out_type: $opt\n"; + exit (1); + } +} + +# 'antialias|aa=i' => \$antialias, +# 'noantialias|noaa' => sub { $antialias = 0 }, +# 'scale=f' => \$scale, +# 'width=i' => \$width, +# 'height=i' => \$height, +# 'resolution=i' => \$res, + +# die ("Antialias value must be 0, 1, 2, 4, or 8\n") + +# -width XXX desired with +# -height XXX desired height +# -resolution XXX resolution (default = $res) +# -scale XXX scaling factor +# -antialias XX antialias factor (must be 0, 1, 2, 4 or 8; default: 4) +# -noantialias no antialiasing (same as -antialias 0) + +1; diff --git a/httemplate/config/config-image.cgi b/httemplate/config/config-image.cgi index 892f7c65b..0de9d4278 100644 --- a/httemplate/config/config-image.cgi +++ b/httemplate/config/config-image.cgi @@ -1,4 +1,4 @@ -<% $conf->config_binary($name, $agentnum) %> +<% $logo %> <%init> die "access denied" @@ -16,4 +16,7 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { $agentnum = $1; } +my $logo = $conf->config_binary($name, $agentnum); +$logo = eps2png($logo) if $name =~ /\.eps$/i; + diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index 0f5fd6213..f2ae892a6 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -69,22 +69,32 @@ Click on a configuration value to change it. % } elsif ( $type eq 'image' ) { - - <% $conf->exists($i->key, $agentnum) - ? '' - : 'empty' - %> + + + + % } elsif ( $type eq 'binary' ) { - - <% $conf->exists($i->key, $agentnum) - ? qq!download! - : 'empty' - %> + % } elsif ( $type eq 'textarea' diff --git a/httemplate/docs/credits.html b/httemplate/docs/credits.html index 3c5564da3..38d384bcf 100644 --- a/httemplate/docs/credits.html +++ b/httemplate/docs/credits.html @@ -33,7 +33,7 @@
-

Core team

+

Core Team

Peter Bowen
Jeff Finucane
Jason Hall
@@ -42,6 +42,11 @@ Ivan Kohler
Richard Siddall

+

Core Emeritus

+Brian McCane
+Matt Simerson
+
+

Contributors

Stephen Amadei
Eric Arvidsson
@@ -57,6 +62,7 @@ Rebecca Cardennis
Shane Chrisp
Luke Crawford
Brad Dameron
+Jeremy Davis
Dave Denney
Serge Dolgov
Scott Edwards
@@ -74,19 +80,18 @@ Greg Kuhnert
Randall Lucas
Foteos Macrides
Roger Mangraviti
-Brian McCane
mimooh
Mack Nagashima
Matt Peterson
Luke Pfeifer
Ricardo Signes
-Matt Simerson
Steve Simitzis
Jason Spence
James Switzer
Audrey Tang
Jason Thomas
Jesse Vincent
+Johan Vromans
Mark Wells
Peter Wemm
Mark Williamson
diff --git a/httemplate/docs/license.html b/httemplate/docs/license.html index 54537307e..a673bc9dd 100644 --- a/httemplate/docs/license.html +++ b/httemplate/docs/license.html @@ -100,6 +100,10 @@ terms of the BSD license.
© 2005 modernmethod, inc
Perl backend version © 2005 Nathan Schmidt +

+Contains code derived from eps2png by Johan Vromans, licensed under the same +terms as Perl (GPL/Artistic). +

-- cgit v1.2.1 From 455342c5657299275c14741ad459ff2ce4f03559 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 09:59:30 +0000 Subject: less debugging --- FS/FS/Misc/eps2png.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FS/FS/Misc/eps2png.pm b/FS/FS/Misc/eps2png.pm index 49c1d5682..c175b3be8 100644 --- a/FS/FS/Misc/eps2png.pm +++ b/FS/FS/Misc/eps2png.pm @@ -37,7 +37,7 @@ my $DEF_height; # desired height #my $DEF_width = 90; # desired widht #my $DEF_height = 36; # desired height -my ($verbose,$trace,$test,$debug) = (0,0,0,1); +my ($verbose,$trace,$test,$debug) = (0,0,0,0); #handle_options (); set_out_type ('png'); # unless defined $format; warn "Producing $format ($gs_format) image.\n" if $verbose; @@ -66,7 +66,7 @@ sub eps2png { my @eps = split(/\r?\n/, $eps); warn "converting eps (". length($eps). " bytes, ". scalar(@eps). " lines)\n" - ;#if $verbose; + if $verbose; my $line = shift @eps; #; unless ( $eps =~ /^%!PS-Adobe.*EPSF-/ ) { -- cgit v1.2.1 From 4445165860112be241b1a51c50436ad0828a297a Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 12:01:25 +0000 Subject: agent-virt invoice_*{notes,footer,smallfooter,coupon}, RT#5025 --- FS/FS/Conf.pm | 6 ++++++ FS/FS/cust_bill.pm | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 8ea57304c..67ce56c6d 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -818,6 +818,7 @@ worry that config_items is freeside-specific and icky. 'section' => 'billing', 'description' => 'Notes section for HTML invoices. Defaults to the same data in invoice_latexnotes if not specified.', 'type' => 'textarea', + 'per_agent' => 1, }, { @@ -825,6 +826,7 @@ worry that config_items is freeside-specific and icky. 'section' => 'billing', 'description' => 'Footer for HTML invoices. Defaults to the same data in invoice_latexfooter if not specified.', 'type' => 'textarea', + 'per_agent' => 1, }, { @@ -846,6 +848,7 @@ worry that config_items is freeside-specific and icky. 'section' => 'billing', 'description' => 'Notes section for LaTeX typeset PostScript invoices.', 'type' => 'textarea', + 'per_agent' => 1, }, { @@ -853,6 +856,7 @@ worry that config_items is freeside-specific and icky. 'section' => 'billing', 'description' => 'Footer for LaTeX typeset PostScript invoices.', 'type' => 'textarea', + 'per_agent' => 1, }, { @@ -860,6 +864,7 @@ worry that config_items is freeside-specific and icky. 'section' => 'billing', 'description' => 'Remittance coupon for LaTeX typeset PostScript invoices.', 'type' => 'textarea', + 'per_agent' => 1, }, { @@ -874,6 +879,7 @@ worry that config_items is freeside-specific and icky. 'section' => 'billing', 'description' => 'Optional small footer for multi-page LaTeX typeset PostScript invoices.', 'type' => 'textarea', + 'per_agent' => 1, }, { diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index c8384c009..6fac0a946 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -1990,15 +1990,18 @@ sub print_generic { $invoice_data{'previous_balance'} = sprintf("%.2f", $pr_total); $invoice_data{'balance'} = sprintf("%.2f", $balance_due); + my $agentnum = $self->cust_main->agentnum; + #do variable substitution in notes, footer, smallfooter foreach my $include (qw( notes footer smallfooter coupon )) { my $inc_file = $conf->key_orbase("invoice_${format}$include", $template); my @inc_src; - if ( $conf->exists($inc_file) && length( $conf->config($inc_file) ) ) { + if ( $conf->exists($inc_file, $agentnum) + && length( $conf->config($inc_file, $agentnum) ) ) { - @inc_src = $conf->config($inc_file); + @inc_src = $conf->config($inc_file, $agentnum); } else { @@ -2010,7 +2013,7 @@ sub print_generic { s/--\@\]/$delimiters{$format}[1]/g; $_; } - &$convert_map( $conf->config($inc_file) ); + &$convert_map( $conf->config($inc_file, $agentnum) ); } -- cgit v1.2.1 From e20a3591dee00904c2def9cd68207d941eaf43b4 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 17 Mar 2009 16:06:31 +0000 Subject: column upgrade for tax_rate RT#4903) --- FS/FS/Upgrade.pm | 3 +++ FS/FS/tax_rate.pm | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm index 97f24d403..5abfa6940 100644 --- a/FS/FS/Upgrade.pm +++ b/FS/FS/Upgrade.pm @@ -126,6 +126,9 @@ sub upgrade_data { #fixup access rights 'access_right' => [], + #change tax_rate column types + 'tax_rate' => [], + ; \%hash; diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index 0d9156b43..3323e0060 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -3,11 +3,14 @@ package FS::tax_rate; use strict; use vars qw( @ISA $DEBUG $me %tax_unittypes %tax_maxtypes %tax_basetypes %tax_authorities - %tax_passtypes ); + %tax_passtypes %GetInfoType ); use Date::Parse; use Storable qw( thaw ); use MIME::Base64; -use FS::Record qw( qsearch qsearchs dbh ); +use DBIx::DBSchema; +use DBIx::DBSchema::Table; +use DBIx::DBSchema::Column; +use FS::Record qw( qsearch qsearchs dbh dbdef ); use FS::tax_class; use FS::cust_bill_pkg; use FS::cust_tax_location; @@ -1063,6 +1066,67 @@ sub browse_queries { return ($query, "SELECT COUNT(*) FROM tax_rate $extra_sql"); } +# _upgrade_data +# +# Used by FS::Upgrade to migrate to a new database. +# +# + +sub _upgrade_data { # class method + my ($self, %opts) = @_; + my $dbh = dbh; + + warn "$me upgrading $self\n" if $DEBUG; + + my @column = qw ( tax excessrate usetax useexcessrate fee excessfee + feebase feemax ); + + if ( $dbh->{Driver}->{Name} eq 'Pg' ) { + + eval "use DBI::Const::GetInfoType;"; + die $@ if $@; + + my $major_version = 0; + $dbh->get_info( $GetInfoType{SQL_DBMS_VER} ) =~ /^(\d{2})/ + && ( $major_version = sprintf("%d", $1) ); + + if ( $major_version > 7 ) { + + # ideally this would be supported in DBIx-DBSchema and friends + + foreach my $column ( @column ) { + my $columndef = dbdef->table($self->table)->column($column); + unless ($columndef->type eq 'numeric') { + + warn "updating tax_rate column $column to numeric\n" if $DEBUG; + my $sql = "ALTER TABLE tax_rate ALTER $column TYPE numeric(14,8)"; + my $sth = $dbh->prepare($sql) or die $dbh->errstr; + $sth->execute or die $sth->errstr; + + warn "updating h_tax_rate column $column to numeric\n" if $DEBUG; + $sql = "ALTER TABLE h_tax_rate ALTER $column TYPE numeric(14,8)"; + $sth = $dbh->prepare($sql) or die $dbh->errstr; + $sth->execute or die $sth->errstr; + + } + } + + } else { + + warn "WARNING: tax_rate table upgrade unsupported for this Pg version\n"; + + } + + } else { + + warn "WARNING: tax_rate table upgrade only supported for Pg 8+\n"; + + } + + ''; + +} + =back =head1 BUGS -- cgit v1.2.1 From 968936c184fd0ba1d00ce5939569e7e0bbcb6c24 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 19:48:32 +0000 Subject: adding ClientAPI/SGNG.pm --- FS/FS/ClientAPI/SGNG.pm | 256 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 FS/FS/ClientAPI/SGNG.pm diff --git a/FS/FS/ClientAPI/SGNG.pm b/FS/FS/ClientAPI/SGNG.pm new file mode 100644 index 000000000..6f74e23a0 --- /dev/null +++ b/FS/FS/ClientAPI/SGNG.pm @@ -0,0 +1,256 @@ +#this stuff is SG-specific (i.e. multi-customer company username hack) + +package FS::ClientAPI::SGNG; + +use strict; +use vars qw( $cache $DEBUG ); +use Time::Local qw(timelocal timelocal_nocheck); +use Business::CreditCard; +use FS::Record qw( qsearch qsearchs ); +use FS::cust_main; +use FS::cust_pkg; +use FS::ClientAPI::MyAccount; #qw( payment_info process_payment ) + +$DEBUG = 0; + +sub _cache { + $cache ||= new FS::ClientAPI_SessionCache( { + 'namespace' => 'FS::ClientAPI::MyAccount', #yes, share session_ids + } ); +} + +#this might almost be general-purpose +sub decompify_pkgs { + my $p = shift; + + my $session = _cache->get($p->{'session_id'}) + or return { 'error' => "Can't resume session" }; #better error message + + my $custnum = $session->{'custnum'}; + + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or return { 'error' => "unknown custnum $custnum" }; + + return { 'error' => 'Not a complimentary customer' } + unless $cust_main->payby eq 'COMP'; + + my $paydate = + $cust_main->paydate =~ /^\S+$/ ? $cust_main->paydate : '2037-12-31'; + + my ($payyear,$paymonth,$payday) = split (/-/,$paydate); + + my $date = timelocal(0,0,0,$payday,--$paymonth,$payyear); + + foreach my $cust_pkg ( + qsearch({ 'table' => 'cust_pkg', + 'hashref' => { 'custnum' => $custnum, + 'bill' => '', + }, + 'extra_sql' => ' AND '. FS::cust_pkg->active_sql, + }) + ) { + $cust_pkg->set('bill', $date); + my $error = $cust_pkg->replace; + return { 'error' => $error } if $error; + } + + return { 'error' => '' }; + +} + +#find old payment info +# (should work just like MyAccount::payment_info, except returns previous info +# too) +# definitly sg-specific, no one else stores past customer records like this +sub previous_payment_info { + my $p = shift; + + my $session = _cache->get($p->{'session_id'}) + or return { 'error' => "Can't resume session" }; #better error message + + my $payment_info = FS::ClientAPI::MyAccount::payment_info($p); + + my $custnum = $session->{'custnum'}; + + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or return { 'error' => "unknown custnum $custnum" }; + + #? + return $payment_info if $cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/; + + foreach my $prev_cust_main ( + reverse _previous_cust_main( 'custnum' => $custnum, + 'username' => $cust_main->company, + 'with_payments' => 1, + ) + ) { + + next unless $prev_cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/; + + if ( $prev_cust_main->payby =~ /^(CARD|DCRD)$/ ) { + + #card expired? + my ($payyear,$paymonth,$payday) = split (/-/, $cust_main->paydate); + + my $expdate = timelocal_nocheck(0,0,0,1,$paymonth,$payyear); + + next if $expdate < time; + + } elsif ( $prev_cust_main->payby =~ /^(CHEK|DCHK)$/ ) { + + #any check? or just skip these in favor of cards? + + } + + return { %$payment_info, + #$prev_cust_main->payment_info + _cust_main_payment_info( $prev_cust_main ), + 'previous_custnum' => $prev_cust_main->custnum, + }; + + } + + #still nothing? return an error? + return $payment_info; + +} + +#this is really FS::cust_main::payment_info, but here for now +sub _cust_main_payment_info { + my $self = shift; + + my %return = (); + + $return{balance} = $self->balance; + + $return{payname} = $self->payname + || ( $self->first. ' '. $self->get('last') ); + + $return{$_} = $self->get($_) for qw(address1 address2 city state zip); + + $return{payby} = $self->payby; + $return{stateid_state} = $self->stateid_state; + + if ( $self->payby =~ /^(CARD|DCRD)$/ ) { + $return{card_type} = cardtype($self->payinfo); + $return{payinfo} = $self->paymask; + + @return{'month', 'year'} = $self->paydate_monthyear; + + } + + if ( $self->payby =~ /^(CHEK|DCHK)$/ ) { + my ($payinfo1, $payinfo2) = split '@', $self->paymask; + $return{payinfo1} = $payinfo1; + $return{payinfo2} = $payinfo2; + $return{paytype} = $self->paytype; + $return{paystate} = $self->paystate; + + } + + #doubleclick protection + my $_date = time; + $return{paybatch} = "webui-MyAccount-$_date-$$-". rand() * 2**32; + + %return; + +} + +#find old cust_main records (with payments) +sub _previous_cust_main { + my %opt = @_; + my $custnum = $opt{'custnum'}; + my $username = $opt{'username'}; + + my %search = (); + if ( $opt{'with_payments'} ) { + $search{'extra_sql'} = + ' AND 0 < ( SELECT COUNT(*) FROM cust_pay + WHERE cust_pay.custnum = cust_main.custnum + ) + '; + } + + qsearch( { + 'table' => 'cust_main', + 'hashref' => { 'company' => { op => 'ILIKE', value => $opt{'username'} }, + 'custnum' => { op => '!=', value => $opt{'custnum'} }, + }, + 'order_by' => 'ORDER BY custnum', + %search, + } ); + +} + +#since we could be passing masked old CC data, need to look that up and +#replace it (like regular process_payment does) w/info from old customer record +sub previous_process_payment { + my $p = shift; + + return FS::ClientAPI::MyAccount::process_payment($p) + unless $p->{'previous_custnum'} + && ( ( $p->{'payby'} =~ /^(CARD|DCRD)$/ && $p->{'payinfo'} =~ /x/i ) + || ( $p->{'payby'} =~ /^(CHEK|DCHK)$/ && $p->{'payinfo1'} =~ /x/i ) + ); + + my $session = _cache->get($p->{'session_id'}) + or return { 'error' => "Can't resume session" }; #better error message + + my $custnum = $session->{'custnum'}; + + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or return { 'error' => "unknown custnum $custnum" }; + + #make sure this is really a previous custnum of this customer + my @previous_cust_main = + grep { $_->custnum == $p->{'previous_custnum'} } + _previous_cust_main( 'custnum' => $custnum, + 'username' => $cust_main->company, + 'with_payments' => 1, + ); + + my $previous_cust_main = $previous_cust_main[0]; + + #causes problems with old data w/old masking method + #if $previous_cust_main->paymask eq $payinfo; + + if ( $p->{'payby'} =~ /^(CHEK|DCHK)$/ && $p->{'payinfo1'} =~ /x/i ) { + ( $p->{'payinfo1'}, $p->{'payinfo2'} ) = + split('@', $previous_cust_main->payinfo); + } elsif ( $p->{'payby'} =~ /^(CARD|DCRD)$/ && $p->{'payinfo'} =~ /x/i ) { + $p->{'payinfo'} = $previous_cust_main->payinfo; + } + + FS::ClientAPI::MyAccount::process_payment($p); + +} + +sub previous_process_payment_order_pkg { + my $p = shift; + + my $hr = previous_process_payment($p); + return $hr if $hr->{'error'}; + + order_pkg($p); +} + +sub previous_process_payment_change_pkg { + my $p = shift; + + my $hr = previous_process_payment($p); + return $hr if $hr->{'error'}; + + change_pkg($p); +} + +sub previous_process_payment_order_renew { + my $p = shift; + + my $hr = previous_process_payment($p); + return $hr if $hr->{'error'}; + + order_renew($p); +} + +1; + -- cgit v1.2.1 From d8942379e744c35b50c3f43ef68ef78afbfad243 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 20:04:16 +0000 Subject: apacheip isn't actually deprecated yet --- FS/FS/Conf.pm | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 67ce56c6d..9197bb153 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -573,8 +573,11 @@ worry that config_items is freeside-specific and icky. { 'key' => 'apacheip', - 'section' => 'deprecated', - 'description' => 'DEPRECATED, add an apache export instead. Used to be the current IP address to assign to new virtual hosts', + #not actually deprecated yet + #'section' => 'deprecated', + #'description' => 'DEPRECATED, add an apache export instead. Used to be the current IP address to assign to new virtual hosts', + 'section' => '', + 'description' => 'IP address to assign to new virtual hosts', 'type' => 'text', }, @@ -686,8 +689,11 @@ worry that config_items is freeside-specific and icky. { 'key' => 'deletecredits', - 'section' => 'deprecated', - 'description' => 'DEPRECATED, now controlled by ACLs. Used to enable deletion of unclosed credits. Be very careful! Only delete credits that were data-entry errors, not adjustments. Optionally specify one or more comma-separated email addresses to be notified when a credit is deleted.', + #not actually deprecated yet + #'section' => 'deprecated', + #'description' => 'DEPRECATED, now controlled by ACLs. Used to enable deletion of unclosed credits. Be very careful! Only delete credits that were data-entry errors, not adjustments. Optionally specify one or more comma-separated email addresses to be notified when a credit is deleted.', + 'section' => '', + 'description' => 'One or more comma-separated email addresses to be notified when a credit is deleted.', 'type' => [qw( checkbox text )], }, -- cgit v1.2.1 From 82e3d70fea83fb776473e082097e2978226e3960 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 20:13:26 +0000 Subject: add a conf switch to enable sg multicust stuff, since it could be dangerous --- FS/FS/Conf.pm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 9197bb153..f765fc721 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2705,6 +2705,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'sg-multicustomer_hack', + 'section' => '', + 'description' => "Don't use this.", + 'type' => 'checkbox', + }, + ); 1; -- cgit v1.2.1 From 106bc3bf631b49daafa890bd092a3f8c5084adb3 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 20:41:06 +0000 Subject: add SG stuff --- fs_selfservice/FS-SelfService/SelfService.pm | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index 3ede27cd9..fda3e8596 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -37,6 +37,7 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'payment_info' => 'MyAccount/payment_info', 'process_payment' => 'MyAccount/process_payment', 'process_payment_order_pkg' => 'MyAccount/process_payment_order_pkg', + 'process_payment_change_pkg' => 'MyAccount/process_payment_change_pkg', 'process_payment_order_renew' => 'MyAccount/process_payment_order_renew', 'process_prepay' => 'MyAccount/process_prepay', 'realtime_collect' => 'MyAccount/realtime_collect', @@ -68,6 +69,16 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'call_time' => 'PrepaidPhone/call_time', 'call_time_nanpa' => 'PrepaidPhone/call_time_nanpa', 'phonenum_balance' => 'PrepaidPhone/phonenum_balance', + #sg + 'decompify_pkgs' => 'SGNG/decompify_pkgs', + 'previous_payment_info' => 'SGNG/previous_payment_info', + 'previous_process_payment' => 'SGNG/previous_process_payment', + 'previous_process_payment_order_pkg' + => 'SGNG/previous_process_payment_order_pkg', + 'previous_process_payment_change_pkg' + => 'SGNG/previous_process_payment_change_pkg', + 'previous_process_payment_order_renew' + => 'SGNG/previous_process_payment_order_renew', ); @EXPORT_OK = ( keys(%autoload), @@ -570,6 +581,16 @@ as parameter with the keys of both methods. Returns a hash reference with a single key, B, empty on success, or an error message on errors. +=item process_payment_change_pkg + +Combines the B and B functions in one step. If the +payment processes sucessfully, the package is ordered. Takes a hash reference +as parameter with the keys of both methods. + +Returns a hash reference with a single key, B, empty on success, or an +error message on errors. + + =item process_payment_order_renew Combines the B and B functions in one step. If @@ -851,6 +872,31 @@ Returns a hash reference with a single key, B, empty on success, or an error message on errors. The special error '_decline' is returned for declined transactions. +=item change_pkg + +Changes a package for this customer. + +Takes a hash reference as parameter with the following keys: + +=over 4 + +=item session_id + +Session identifier + +=item pkgnum + +Existing customer package. + +=item pkgpart + +New package to order (see L). + +=back + +Returns a hash reference with a single key, B, empty on success, or an +error message on errors. + =item renew_info Provides useful info for early renewals. -- cgit v1.2.1 From c72e127acc79a61703223e6c8b504abd234ca8b3 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 21:38:39 +0000 Subject: add payment_info_renew_info method to ClientAPI/MyAccount and SG-equivalent previous_payment_info_renew_info to ClientAPI/SGNG --- FS/FS/ClientAPI/MyAccount.pm | 22 +++++++++++++++++----- FS/FS/ClientAPI/SGNG.pm | 14 ++++++++++++++ fs_selfservice/FS-SelfService/SelfService.pm | 14 ++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index c6a4e0058..564acb1a6 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -1162,11 +1162,14 @@ sub renew_info { $total += $_->part_pkg->base_recur; my $renew_date = $_->part_pkg->add_freq($_->bill); { - 'bill_date' => $_->bill, - 'bill_date_pretty' => time2str('%x', $_->bill), - 'renew_date' => $renew_date, - 'renew_date_pretty' => time2str('%x', $renew_date), - 'amount' => sprintf('%.2f', $total), + 'pkgnum' => $_->pkgnum, + 'amount' => sprintf('%.2f', $total), + 'bill_date' => $_->bill, + 'bill_date_pretty' => time2str('%x', $_->bill), + 'renew_date' => $renew_date, + 'renew_date_pretty' => time2str('%x', $renew_date), + 'expire_date' => $_->expire, + 'expire_date_pretty' => time2str('%x', $_->expire), }; } @cust_pkg; @@ -1175,6 +1178,15 @@ sub renew_info { } +sub payment_info_renew_info { + my $p = shift; + my $renew_info = renew_info($p); + my $payment_info = payment_info($p); + return { %$renew_info, + %$payment_info, + }; +} + sub order_renew { my $p = shift; diff --git a/FS/FS/ClientAPI/SGNG.pm b/FS/FS/ClientAPI/SGNG.pm index 6f74e23a0..872148abd 100644 --- a/FS/FS/ClientAPI/SGNG.pm +++ b/FS/FS/ClientAPI/SGNG.pm @@ -7,6 +7,7 @@ use vars qw( $cache $DEBUG ); use Time::Local qw(timelocal timelocal_nocheck); use Business::CreditCard; use FS::Record qw( qsearch qsearchs ); +use FS::Conf; use FS::cust_main; use FS::cust_pkg; use FS::ClientAPI::MyAccount; #qw( payment_info process_payment ) @@ -158,6 +159,10 @@ sub _cust_main_payment_info { #find old cust_main records (with payments) sub _previous_cust_main { + + #safety check! return nothing unless we're enabled explicitly + return () unless FS::Conf->new->exists('sg-multicustomer_hack'); + my %opt = @_; my $custnum = $opt{'custnum'}; my $username = $opt{'username'}; @@ -225,6 +230,15 @@ sub previous_process_payment { } +sub previous_payment_info_renew_info { + my $p = shift; + my $renew_info = renew_info($p); + my $payment_info = previous_payment_info($p); + return { %$renew_info, + %$payment_info, + }; +} + sub previous_process_payment_order_pkg { my $p = shift; diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index fda3e8596..b4b9ecf29 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -944,6 +944,20 @@ Specified as a integer UNIX timestamp. Renewal date as a human-readable string. (Convenience for display; subject to change, so best not to parse for the date.) +=item pkgnum + +Package that will be renewed. + +=item expire_date + +Expiration date of the package that will be renewed. + +=item expire_date_pretty + +Expiration date of the package that will be renewed, as a human-readable +string. (Convenience for display; subject to change, so best not to parse for +the date.) + =back =item order_renew -- cgit v1.2.1 From e61679ab66b5e1e2db39791117440d7dfce41045 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Mar 2009 22:02:36 +0000 Subject: add payment_info_renew_info method to ClientAPI/MyAccount and SG-equivalent previous_payment_info_renew_info to ClientAPI/SGNG --- fs_selfservice/FS-SelfService/SelfService.pm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index b4b9ecf29..fef211580 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -35,6 +35,7 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'list_invoices' => 'MyAccount/list_invoices', #? 'cancel' => 'MyAccount/cancel', #add to ss cgi! 'payment_info' => 'MyAccount/payment_info', + 'payment_info_renew_info' => 'MyAccount/payment_info_renew_info', 'process_payment' => 'MyAccount/process_payment', 'process_payment_order_pkg' => 'MyAccount/process_payment_order_pkg', 'process_payment_change_pkg' => 'MyAccount/process_payment_change_pkg', @@ -72,6 +73,8 @@ $socket .= '.'.$tag if defined $tag && length($tag); #sg 'decompify_pkgs' => 'SGNG/decompify_pkgs', 'previous_payment_info' => 'SGNG/previous_payment_info', + 'previous_payment_info_renew_info' + => 'SGNG/previous_payment_info_renew_info', 'previous_process_payment' => 'SGNG/previous_process_payment', 'previous_process_payment_order_pkg' => 'SGNG/previous_process_payment_order_pkg', -- cgit v1.2.1 From 037c3acd250f637182019d0a74361d5420f29c52 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 18 Mar 2009 00:30:43 +0000 Subject: hide unused usage columns --- FS/FS/part_pkg/flat.pm | 11 ++++++++--- FS/FS/svc_acct.pm | 29 +++++++++++++++++++++++++++++ httemplate/edit/part_svc.cgi | 9 ++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index 3ac44c4e2..8fd028650 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -195,12 +195,17 @@ sub is_prepaid { 0; #no, we're postpaid } +sub usage_valuehash { + my $self = shift; + map { $_, $self->option($_) } + grep { $self->option($_, 'hush') } + qw(seconds upbytes downbytes totalbytes); +} + sub reset_usage { my($self, $cust_pkg, %opt) = @_; warn " resetting usage counters" if $opt{debug} > 1; - my %values = map { $_, $self->option($_) } - grep { $self->option($_, 'hush') } - qw(seconds upbytes downbytes totalbytes); + my %values = $self->usage_valuehash; if ($self->option('usage_rollover', 1)) { $cust_pkg->recharge(\%values); }else{ diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 6f1105148..57ef615f9 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -26,6 +26,7 @@ use FS::Conf; use FS::Record qw( qsearch qsearchs fields dbh dbdef ); use FS::Msgcat qw(gettext); use FS::UI::bytecount; +use FS::part_pkg; use FS::svc_Common; use FS::cust_svc; use FS::part_svc; @@ -277,6 +278,7 @@ sub table_info { type => 'text', disable_inventory => 1, disable_select => 1, + disable_part_svc_column => 1, }, 'upbytes' => { label => 'Upload', type => 'text', @@ -284,6 +286,7 @@ sub table_info { disable_select => 1, 'format' => \&FS::UI::bytecount::display_bytecount, 'parse' => \&FS::UI::bytecount::parse_bytecount, + disable_part_svc_column => 1, }, 'downbytes' => { label => 'Download', type => 'text', @@ -291,6 +294,7 @@ sub table_info { disable_select => 1, 'format' => \&FS::UI::bytecount::display_bytecount, 'parse' => \&FS::UI::bytecount::parse_bytecount, + disable_part_svc_column => 1, }, 'totalbytes'=> { label => 'Total up and download', type => 'text', @@ -298,11 +302,13 @@ sub table_info { disable_select => 1, 'format' => \&FS::UI::bytecount::display_bytecount, 'parse' => \&FS::UI::bytecount::parse_bytecount, + disable_part_svc_column => 1, }, 'seconds_threshold' => { label => 'Seconds threshold', type => 'text', disable_inventory => 1, disable_select => 1, + disable_part_svc_column => 1, }, 'upbytes_threshold' => { label => 'Upload threshold', type => 'text', @@ -310,6 +316,7 @@ sub table_info { disable_select => 1, 'format' => \&FS::UI::bytecount::display_bytecount, 'parse' => \&FS::UI::bytecount::parse_bytecount, + disable_part_svc_column => 1, }, 'downbytes_threshold' => { label => 'Download threshold', type => 'text', @@ -317,6 +324,7 @@ sub table_info { disable_select => 1, 'format' => \&FS::UI::bytecount::display_bytecount, 'parse' => \&FS::UI::bytecount::parse_bytecount, + disable_part_svc_column => 1, }, 'totalbytes_threshold'=> { label => 'Total up and download threshold', type => 'text', @@ -324,6 +332,7 @@ sub table_info { disable_select => 1, 'format' => \&FS::UI::bytecount::display_bytecount, 'parse' => \&FS::UI::bytecount::parse_bytecount, + disable_part_svc_column => 1, }, 'last_login'=> { label => 'Last login', @@ -503,6 +512,26 @@ sub insert { $self->svcpart($cust_svc->svcpart); } + # set usage fields and thresholds if unset but set in a package def + if ( $self->pkgnum ) { + my $cust_pkg = qsearchs( 'cust_pkg', { 'pkgnum' => $self->pkgnum } ); + my $part_pkg = $cust_pkg->part_pkg if $cust_pkg; + if ( $part_pkg && $part_pkg->can('usage_valuehash') ) { + + my %values = $part_pkg->usage_valuehash; + my $multiplier = $conf->exists('svc_acct-usage_threshold') + ? 1 - $conf->config('svc_acct-usage_threshold')/100 + : 0.20; + + foreach ( keys %values ) { + next if $self->getfield($_); + $self->setfield( $_, $values{$_} ); + $self->setfield( $_. '_threshold', int( $values{$_} * $multiplier ) ); + } + + } + } + my @jobnums; $error = $self->SUPER::insert( 'jobnums' => \@jobnums, diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index e0fb615b1..deb3c80f9 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -131,7 +131,14 @@ that field. % % #yucky kludge % my @fields = defined( dbdef->table($layer) ) -% ? grep { $_ ne 'svcnum' } fields($layer) +% ? grep { +% $_ ne 'svcnum' && +% ( !FS::part_svc->svc_table_fields($layer) +% ->{$_}->{disable_part_svc_column} || +% $part_svc->part_svc_column($_)->columnflag +% ) +% } +% fields($layer) % : (); % push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge % $part_svc->svcpart($clone) if $clone; #haha, undone below -- cgit v1.2.1 From b8a433b04fc02ae5b246be8f05a0d3b4f8b79d18 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 18 Mar 2009 15:11:03 +0000 Subject: more error information --- FS/FS/part_pkg_taxrate.pm | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/FS/FS/part_pkg_taxrate.pm b/FS/FS/part_pkg_taxrate.pm index 6d1414a18..197bf0fc4 100644 --- a/FS/FS/part_pkg_taxrate.pm +++ b/FS/FS/part_pkg_taxrate.pm @@ -295,10 +295,18 @@ sub batch_import { delete($hash->{actionflag}); my $part_pkg_taxrate = qsearchs('part_pkg_taxrate', $hash); - return "Can't find part_pkg_taxrate to delete: ". - #join(" ", map { "$_ => ". $hash->{$_} } @fields) - join(" ", map { "$_ => *". $hash->{$_}. '*' } keys(%$hash) ) - unless $part_pkg_taxrate; + unless ( $part_pkg_taxrate ) { + if ( $hash->{taxproductnum} ) { + my $taxproduct = + qsearchs( 'part_pkg_taxproduct', + { 'taxproductnum' => $hash->{taxproductnum} } + ); + $hash->{taxproductnum} .= ' ( '. $taxproduct->taxproduct. ' )' + if $taxproduct; + } + return "Can't find part_pkg_taxrate to delete: ". + join(" ", map { "$_ => *". $hash->{$_}. '*' } keys(%$hash) ); + } my $error = $part_pkg_taxrate->delete; return $error if $error; -- cgit v1.2.1 From 4e7273f1dee05cf62089ce43960313674b66fbcd Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 20 Mar 2009 02:14:17 +0000 Subject: adding quick remote ping & alert script, RT#4610 --- bin/ping | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 bin/ping diff --git a/bin/ping b/bin/ping new file mode 100755 index 000000000..605a2047e --- /dev/null +++ b/bin/ping @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +use Net::Ping; +use Net::SSH qw( ssh_cmd ); +use Email::Send; + +my @other_hosts = ( 'freeside.biz', 'saturn5.com' ); + +my( $machine, @emails ) = @ARGV; +die "no notification email given" unless @emails; + +my $ping = new Net::Ping; # 'icmp'; #requires root + +my $pong = ''; +# can't tcp ping... $ping->ping($machine) and +$pong = eval { ssh_cmd('freeside@'.$machine, 'echo pong') }; +#(command ignored if authorized_keys setup w/command=) + +if ( $@ || $pong !~ /pong/ ) { #houston, we may have a problem + + #warn "can't reach $machine, checking @other_hosts\n"; + + #let's do a sanity check, can we see some other hosts? + exit unless grep $ping->ping($_), @other_hosts; + + #uh-oh, this is bad. + + #warn "checking to see if we've alerted on this recently\n"; + + #but we don't want to be too noisy, have we alerted on this in the last 24h? + my $file = "/tmp/alert-$machine"; + exit if -e $file && -M $file < 1; + + open(FILE, ">>$file"); + print FILE "emailing\n"; + close FILE; + + #warn "emailing alerts\n"; + + foreach my $email ( @emails ) { + + my $message = <<"__MESSAGE__"; +From: support\@freeside.biz +To: $email +Subject: ALERT - $machine + +ALERT: $machine appears to be down. + +__MESSAGE__ + + my $sender = Email::Send->new({mailer => 'SMTP'}); + $sender->mailer_args([Host => 'mail.freeside.biz']); + $sender->send($message); + + } + +} + -- cgit v1.2.1 From 06366964387677bd819ff9603a25d4399d9ad84d Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Mar 2009 22:14:37 +0000 Subject: freeside-check local monitoring, RT#4610 --- FS/FS/Cron/check.pm | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ FS/bin/freeside-check | 24 ++++++++++ Makefile | 4 ++ 3 files changed, 151 insertions(+) create mode 100644 FS/FS/Cron/check.pm create mode 100644 FS/bin/freeside-check diff --git a/FS/FS/Cron/check.pm b/FS/FS/Cron/check.pm new file mode 100644 index 000000000..39dd168b4 --- /dev/null +++ b/FS/FS/Cron/check.pm @@ -0,0 +1,123 @@ +package FS::Cron::check; + +use strict; +use vars qw( @ISA @EXPORT_OK $DEBUG $FS_RUN $error_msg + $SELFSERVICE_USER $SELFSERVICE_MACHINES @SELFSERVICE_MACHINES + ); +use Exporter; +use LWP::UserAgent; +use FS::Conf; +use FS::Record qw(qsearch); +use FS::cust_pay_pending; + +@ISA = qw( Exporter ); +@EXPORT_OK = qw( + check_queued check_selfservice check_apache check_bop_failures + alert error_msg +); + +$DEBUG = 0; + +$FS_RUN = '/var/run'; + +sub check_queued { + _check_fsproc('queued'); +} + +$SELFSERVICE_USER = '%%%SELFSERVICE_USER%%%'; + +$SELFSERVICE_MACHINES = '%%%SELFSERVICE_MACHINES%%%'; #substituted by Makefile +$SELFSERVICE_MACHINES =~ s/^\s+//; +$SELFSERVICE_MACHINES =~ s/\s+$//; +@SELFSERVICE_MACHINES = split(/\s+/, $SELFSERVICE_MACHINES); +@SELFSERVICE_MACHINES = () + if scalar(@SELFSERVICE_MACHINES) == 1 + && $SELFSERVICE_MACHINES[0] eq '%%%'.'SELFSERVICE_MACHINES'.'%%%'; + +sub check_selfservice { + foreach my $machine ( @SELFSERVICE_MACHINES ) { + unless ( _check_fsproc("selfservice-server.$SELFSERVICE_USER.$machine") ) { + $error_msg = "Self-service daemon not running for $machine"; + return 0; + } + } + return 1; +} + +sub _check_fsproc { + my $arg = shift; + _check_pidfile( "freeside-$arg.pid" ); +} + +sub _check_pidfile { + my $pidfile = shift; + open(PID, "$FS_RUN/$pidfile") or return 0; + chomp( my $pid = scalar() ); + close PID; # or return 0; + + $pid && kill 0, $pid; +} + +sub check_apache { + my $ua = new LWP::UserAgent; + $ua->agent("FreesideCronCheck/0.1 " . $ua->agent); + + my $req = new HTTP::Request GET => 'https://localhost/'; + my $res = $ua->request($req); + + return 1 if $res->is_success; + $error_msg = $res->status_line; + return 0; + +} + +#and now for something entirely different... +my $num_consecutive_bop_failures = 10; +sub check_bop_failures { + + return 1 if grep { $_->statustext eq 'captured' } + qsearch({ + 'table' => 'cust_pay_pending', + 'hashref' => { 'status' => 'done' }, + 'order_by' => 'ORDER BY paypendingnum DESC'. + " LIMIT $num_consecutive_bop_failures", + }); + $error_msg = "Last $num_consecutive_bop_failures real-time payments failed"; + return 0; +} + +# + +sub error_msg { + $error_msg; +} + +sub alert { + my( $alert, @emails ) = @_; + + my $conf = new FS::Conf; + my $smtpmachine = $conf->config('smtpmachine'); + my $company_name = $conf->config('company_name'); + + foreach my $email (@emails) { + warn "warning $email about $alert\n" if $DEBUG; + + my $message = <<"__MESSAGE__"; +From: support\@freeside.biz +To: $email +Subject: FREESIDE ALERT for $company_name + +FREESIDE ALERT: $alert + +__MESSAGE__ + + my $sender = Email::Send->new({ mailer => 'SMTP' }); + $sender->mailer_args([ Host => $smtpmachine ]); + $sender->send($message); + + } + +} + +1; + diff --git a/FS/bin/freeside-check b/FS/bin/freeside-check new file mode 100644 index 000000000..09c9aa4f1 --- /dev/null +++ b/FS/bin/freeside-check @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +use strict; +use Email::Send; +use FS::UID qw( adminsuidsetup ); +use FS::Cron::check qw( + check_queued check_selfservice check_apache check_bop_failures + alert error_msg +); + +my $user = shift or die &usage; +my @emails = @ARGV; +#die "no notification email given" unless @emails; + +eval { adminsuidsetup $user }; + +if ( $@ ) { alert("Database down: $@", @emails); exit; } + +check_queued or alert("Queue daemon not running", @emails); +check_selfservice or alert(error_msg(), @emails); +check_apache or alert("Apache not running: ". error_msg(), @emails); + +check_bop_failures or alert(error_msg(), @emails); + diff --git a/Makefile b/Makefile index 59d249837..58275345f 100644 --- a/Makefile +++ b/Makefile @@ -197,6 +197,10 @@ perl-modules: s'%%%RT_ENABLED%%%'${RT_ENABLED}'g; \ s'%%%MASONDATA%%%'${MASONDATA}'g;\ " blib/lib/FS/*.pm;\ + perl -p -i -e "\ + s/%%%SELFSERVICE_USER%%%/${SELFSERVICE_USER}/g;\ + s/%%%SELFSERVICE_MACHINES%%%/${SELFSERVICE_MACHINES}/g;\ + " blib/lib/FS/Cron/*.pm;\ perl -p -i -e "\ s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ " blib/lib/FS/part_export/*.pm;\ -- cgit v1.2.1 From b690d3b4c830c78eb9d3bbf87de399823eaac867 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Mar 2009 23:32:27 +0000 Subject: 403 forbidden is okay, at lest the server's up --- FS/FS/Cron/check.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Cron/check.pm b/FS/FS/Cron/check.pm index 39dd168b4..9a415bd9e 100644 --- a/FS/FS/Cron/check.pm +++ b/FS/FS/Cron/check.pm @@ -65,7 +65,7 @@ sub check_apache { my $req = new HTTP::Request GET => 'https://localhost/'; my $res = $ua->request($req); - return 1 if $res->is_success; + return 1 if $res->is_success || $res->status_line =~ /^403/; $error_msg = $res->status_line; return 0; -- cgit v1.2.1 From dcd8225db25059c0f6fa0c743601eb8945f07692 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 21 Mar 2009 23:37:14 +0000 Subject: Locale::SubCountry warnings clogging up cron output not useful --- FS/bin/freeside-check | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/bin/freeside-check b/FS/bin/freeside-check index 09c9aa4f1..f2d596b80 100644 --- a/FS/bin/freeside-check +++ b/FS/bin/freeside-check @@ -1,3 +1,4 @@ +#!/usr/bin/perl #!/usr/bin/perl -w use strict; -- cgit v1.2.1 From 1613980c5c93d0bdf8699d44ff22ecf828abf122 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 22 Mar 2009 02:47:36 +0000 Subject: fix usps address standardization when the zip returned has no zip+4, RT#4882 --- httemplate/misc/xmlhttp-cust_main-address_standardize.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/httemplate/misc/xmlhttp-cust_main-address_standardize.html b/httemplate/misc/xmlhttp-cust_main-address_standardize.html index 72fa4a464..3b9e142f5 100644 --- a/httemplate/misc/xmlhttp-cust_main-address_standardize.html +++ b/httemplate/misc/xmlhttp-cust_main-address_standardize.html @@ -50,6 +50,9 @@ if ( $sub eq 'address_standardize' ) { unless ( $verifier->is_error ) { + my $zip = $hash->{Zip5}; + $zip .= '-'. $hash->{Zip4} if $hash->{Zip4} =~ /\d/; + $return = { %$return, "new_$pre".'company' => $hash->{FirmName}, @@ -57,7 +60,7 @@ if ( $sub eq 'address_standardize' ) { "new_$pre".'address2' => $hash->{Address1}, "new_$pre".'city' => $hash->{City}, "new_$pre".'state' => $hash->{State}, - "new_$pre".'zip' => $hash->{Zip5}. '-'. $hash->{Zip4}, + "new_$pre".'zip' => $zip, }; my @fields = (qw( company address1 address2 city state zip )); #hmm -- cgit v1.2.1 From 8089deb0915306ba481def7118deb27fe51735ab Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 22 Mar 2009 03:33:40 +0000 Subject: 10 is too few, throwing false positives --- FS/FS/Cron/check.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Cron/check.pm b/FS/FS/Cron/check.pm index 9a415bd9e..e23d62bb4 100644 --- a/FS/FS/Cron/check.pm +++ b/FS/FS/Cron/check.pm @@ -72,7 +72,7 @@ sub check_apache { } #and now for something entirely different... -my $num_consecutive_bop_failures = 10; +my $num_consecutive_bop_failures = 30; sub check_bop_failures { return 1 if grep { $_->statustext eq 'captured' } -- cgit v1.2.1 From 12af08e945ac5c1f593d2bf9cf2d6df09f35228c Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 23 Mar 2009 17:03:03 +0000 Subject: add name (svc_acct.finger) to bulk billing detail, RT#3519 --- FS/FS/part_pkg/bulk.pm | 2 +- FS/FS/svc_Common.pm | 5 +++++ FS/FS/svc_acct.pm | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/FS/FS/part_pkg/bulk.pm b/FS/FS/part_pkg/bulk.pm index 63d344d6d..809559509 100644 --- a/FS/FS/part_pkg/bulk.pm +++ b/FS/FS/part_pkg/bulk.pm @@ -54,7 +54,7 @@ sub calc_recur { # END START foreach my $h_svc ( $cust_pkg->h_cust_svc( $$sdate, $last_bill ) ) { - my @label = $h_svc->label( $$sdate, $last_bill ); + my @label = $h_svc->label_long( $$sdate, $last_bill ); die "fatal: no historical label found, wtf?" unless scalar(@label); #? #my $svc_details = $label[0].': '. $label[1]. ': '; my $svc_details = $label[1]. ': '; diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm index da1cfe135..869ab5831 100644 --- a/FS/FS/svc_Common.pm +++ b/FS/FS/svc_Common.pm @@ -151,6 +151,11 @@ sub label { $self->svcnum; } +sub label_long { + my $self = shift; + $self->label(@_); +} + =item check Checks the validity of fields in this record. diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 57ef615f9..fcd73ac3c 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -256,7 +256,7 @@ sub table_info { disable_inventory => 1, disable_select => 1, }, - 'finger' => 'Real name (GECOS)', + 'finger' => 'Real name', # (GECOS)', 'domsvc' => { label => 'Domain', #def_label => 'svcnum from svc_domain', @@ -446,8 +446,23 @@ sub label { $self->email(@_); } +=item label_long [ END_TIMESTAMP [ START_TIMESTAMP ] ] + +Returns a longer string label for this acccount ("Real Name " +if available, or "username@domain"). + +END_TIMESTAMP and START_TIMESTAMP can optionally be passed when dealing with +history records. + =cut +sub label_long { + my $self = shift; + ( $self->finger =~ /\S/ ) + ? $self->finger. ' <'.$self->label(@_).'>' + : $self->label(@_); +} + =item insert [ , OPTION => VALUE ... ] Adds this account to the database. If there is an error, returns the error, -- cgit v1.2.1 From ad57c5c8513d0980165e3088518ddddeba0db633 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 23 Mar 2009 22:45:42 +0000 Subject: change label for svc_acct.finger from GECOS to "Real Name", RT#3519 --- httemplate/edit/svc_acct.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi index 58283ef54..b9a587d2a 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -168,7 +168,7 @@ Service # <% $svcnum ? "$svcnum" : " (NEW)" %>

- + -- cgit v1.2.1 From 42682206b4ba30de01c82743042f5fb9d48a93ed Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 23 Mar 2009 23:33:04 +0000 Subject: more DTRT with usage on service transfer between packages and recharges RT #2884, #5040 + #4995 fallout --- FS/FS/cust_pkg.pm | 19 +++++++++++++++++-- FS/FS/part_pkg/flat.pm | 2 +- FS/FS/svc_acct.pm | 13 +++++++++---- httemplate/misc/process/recharge_svc.html | 6 +++--- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 7c8656c09..f2c3cccf5 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1135,6 +1135,21 @@ sub change { return "Unable to transfer all services from package ". $self->pkgnum; } + #reset usage if changing pkgpart + if ($self->pkgpart != $cust_pkg->pkgpart) { + my $part_pkg = $cust_pkg->part_pkg; + $error = $part_pkg->reset_usage($cust_pkg, $part_pkg->is_prepaid + ? () + : ( 'null' => 1 ) + ) + if $part_pkg->can('reset_usage'); + + if ($error) { + $dbh->rollback if $oldAutoCommit; + return "Error setting usage values: $error"; + } + } + #Good to go, cancel old package. $error = $self->cancel( quiet=>1 ); if ($error) { @@ -2712,11 +2727,11 @@ All svc_accts which are part of this package have their values reset. =cut sub set_usage { - my ($self, $valueref) = @_; + my ($self, $valueref, %opt) = @_; foreach my $cust_svc ($self->cust_svc){ my $svc_x = $cust_svc->svc_x; - $svc_x->set_usage($valueref) + $svc_x->set_usage($valueref, %opt) if $svc_x->can("set_usage"); } } diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index 8fd028650..009e54c78 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -209,7 +209,7 @@ sub reset_usage { if ($self->option('usage_rollover', 1)) { $cust_pkg->recharge(\%values); }else{ - $cust_pkg->set_usage(\%values); + $cust_pkg->set_usage(\%values, %opt); } } diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index fcd73ac3c..c6857e29a 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1821,7 +1821,7 @@ sub _op_usage { } sub set_usage { - my( $self, $valueref ) = @_; + my( $self, $valueref, %options ) = @_; warn "$me set_usage called for svcnum ". $self->svcnum. ' ('. $self->email. "): ". @@ -1842,6 +1842,11 @@ sub set_usage { my $reset = 0; my %handyhash = (); + if ( $options{null} ) { + %handyhash = ( map { ( $_ => 'NULL', $_."_threshold" => 'NULL' ) } + qw( seconds upbytes downbytes totalbytes ) + ); + } foreach my $field (keys %$valueref){ $reset = 1 if $valueref->{$field}; $self->setfield($field, $valueref->{$field}); @@ -1860,8 +1865,8 @@ sub set_usage { #die $error if $error; #services not explicity changed via the UI my $sql = "UPDATE svc_acct SET " . - join (',', map { "$_ = ?" } (keys %handyhash) ). - " WHERE svcnum = ?"; + join (',', map { "$_ = $handyhash{$_}" } (keys %handyhash) ). + " WHERE svcnum = ". $self->svcnum; warn "$me $sql\n" if $DEBUG; @@ -1869,7 +1874,7 @@ sub set_usage { if (scalar(keys %handyhash)) { my $sth = $dbh->prepare( $sql ) or die "Error preparing $sql: ". $dbh->errstr; - my $rv = $sth->execute((values %handyhash), $self->svcnum); + my $rv = $sth->execute(); die "Error executing $sql: ". $sth->errstr unless defined($rv); die "Can't update usage for svcnum ". $self->svcnum diff --git a/httemplate/misc/process/recharge_svc.html b/httemplate/misc/process/recharge_svc.html index 8c4d13e63..5f68bf151 100755 --- a/httemplate/misc/process/recharge_svc.html +++ b/httemplate/misc/process/recharge_svc.html @@ -1,6 +1,6 @@ %if ($error) { % $cgi->param('error', $error); -<% cgi->redirect(popurl(2). "recharge_svc.html?". $cgi->query_string ) %> +<% $cgi->redirect(popurl(2). "recharge_svc.html?". $cgi->query_string ) %> %} else { <% header("Package recharged") %> + + + + + + +%} + + + + + + +<%init> + +my $conf = new FS::Conf; + +my %opt = @_; + +my $pre_label = $opt{'pre_label'} || ''; +$pre_label .= ' ' if length($pre_label) && $pre_label =~ /\S$/; + +my $cust_main = $opt{'cust_main'} + or die "cust_main not specified"; + +#my @pkg_class = sort { $a->classname cmp $b->classname } +# qsearch( 'pkg_class', { 'disabled' => '' } ); + +#"normal" part_pkg agent virtualization (agentnum or type) +my @part_pkg = qsearch({ + 'select' => 'DISTINCT classnum', + 'table' => 'part_pkg', + 'hashref' => { 'disabled' => '' }, + 'extra_sql' => + ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( 'null'=>1 ). + ' AND '. FS::part_pkg->agent_pkgs_sql( $opt{'cust_main'}->agent ), +}); + +my @pkg_class = + sort { $a->classname cmp $b->classname } #should get a sort order in config + map { $_->pkg_class || new FS::pkg_class { 'classnum' => '', + 'classname' => '(none)' } + } + @part_pkg; + + diff --git a/httemplate/elements/tr-selectmultiple-part_pkg.html b/httemplate/elements/tr-selectmultiple-part_pkg.html index 455038da9..d959a5bae 100644 --- a/httemplate/elements/tr-selectmultiple-part_pkg.html +++ b/httemplate/elements/tr-selectmultiple-part_pkg.html @@ -2,11 +2,10 @@ - - - - - + + <% include('/elements/tr-select-cust-part_pkg.html', + 'pre_label' => 'New', + 'curr_value' => scalar($cgi->param('pkgpart')), + 'classnum' => $part_pkg->classnum, + 'cust_main' => $cust_main, + #'extra_sql' => ' AND pkgpart != '. $cust_pkg->pkgpart, + ) + %> <% include('/elements/tr-select-cust_location.html', 'cgi' => $cgi, diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi new file mode 100644 index 000000000..a249f033f --- /dev/null +++ b/httemplate/misc/cust-part_pkg.cgi @@ -0,0 +1,29 @@ +<% objToJson( \@return ) %> +<%init> + +my( $custnum, $classnum ) = $cgi->param('arg'); + +#XXX i guess i should be agent-virtualized. cause "packages a customer can +#order" is such a huge deal +my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); + +my %hash = ( 'disabled' => '' ); +if ( $classnum > 0 ) { + $hash{'classnum'} = $classnum; +} elsif ( $classnum eq '' || $classnum == 0 ) { + $hash{'classnum'} = ''; +} #else -1, all classes, so don't set classnum + +my @part_pkg = qsearch({ + 'table' => 'part_pkg', + 'hashref' => \%hash, + 'extra_sql' => + ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( 'null'=>1 ). + ' AND '. FS::part_pkg->agent_pkgs_sql( $cust_main->agent ), +}); + +my @return = map { $_->pkgpart => $_->pkg_comment } + sort { $a->pkg_comment cmp $b->pkg_comment } + @part_pkg; + + diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 2c8335154..9caa57a69 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -19,17 +19,13 @@ <% ntable("#cccccc", 2) %> - - - - +<% include('/elements/tr-select-cust-part_pkg.html', + 'curr_value' => $pkgpart, + 'classnum' => -1, + 'cust_main' => $cust_main, + 'onchange' => 'enable_order_pkg', + ) +%> % if ( $conf->exists('pkg_referral') ) { <% include('/elements/tr-select-part_referral.html', -- cgit v1.2.1 From 320bcf3afbae18935ab954d1a738e9502d53955f Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2009 09:38:30 +0000 Subject: optimize customer view when there's lots of packages; *really* avoid looking up any config inside the package loop, RT#5083 --- .../view/cust_main/one_time_charge_link.html | 82 ++++++++++++ httemplate/view/cust_main/packages.html | 142 +++++---------------- httemplate/view/cust_main/packages/status.html | 4 +- 3 files changed, 116 insertions(+), 112 deletions(-) create mode 100644 httemplate/view/cust_main/one_time_charge_link.html diff --git a/httemplate/view/cust_main/one_time_charge_link.html b/httemplate/view/cust_main/one_time_charge_link.html new file mode 100644 index 000000000..6ed70ee4c --- /dev/null +++ b/httemplate/view/cust_main/one_time_charge_link.html @@ -0,0 +1,82 @@ + + + + + + + + + + +<% include('/elements/popup_link.html', { + 'action' => $p.'edit/quick-charge.html?custnum='. $cust_main->custnum, + 'label' => 'One-time charge', + 'actionlabel' => 'One-time charge', + 'color' => '#333399', + 'width' => 763, + 'height' => 408, + }) +%> + +<%init> + +my($cust_main) = @_; + + diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 2c258881a..72846b8ec 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -1,94 +1,25 @@ Packages
-% if ( $curuser->access_right('One-time charge') ) { - - -
- - - - - -% } - % my $s = 0; % if ( $curuser->access_right('Order customer package') ) { <% $s++ ? ' | ' : '' %> - <% order_pkg_link($cust_main) %> + <% include( '/elements/popup_link-cust_main.html', + 'action' => $p. 'misc/order_pkg.html', + 'label' => 'Order new package', + 'actionlabel' => 'Order new package', + 'color' => '#333399', + 'cust_main' => $cust_main, + 'closetext' => 'Close', + 'width' => 763, + ) + %> % } % if ( $curuser->access_right('One-time charge') % && $conf->config('payby-default') ne 'HIDE' % ) { -% <% $s++ ? ' | ' : '' %> - <% include('/elements/popup_link.html', - { - 'action' => $p. 'edit/quick-charge.html?custnum='. $cust_main->custnum, - 'label' => 'One-time charge', - 'actionlabel' => 'One-time charge', - 'color' => '#333399', - 'width' => 763, - 'height' => 408, - }) - %> + <% include('one_time_charge_link.html', $cust_main) %> % } % if ( $curuser->access_right('Bulk change customer packages') ) { @@ -146,24 +77,11 @@ Current packages % $bgcolor = $bgcolor1; % } % -% my $countrydefault = scalar($conf->config('countrydefault')) || 'US'; % my %iopt = ( -% 'bgcolor' => $bgcolor, -% 'cust_pkg' => $cust_pkg, -% 'part_pkg' => $cust_pkg->part_pkg, -% -% #for services.html and status.html -% 'cust_pkg-display_times' => $conf->exists('cust_pkg-display_times'), -% -% #for location.html -% 'countrydefault' => $countrydefault, -% 'statedefault' => ( scalar($conf->config('statedefault')) -% || ($countrydefault eq 'US' ? 'CA' : '') ), -% -% #for services.html -% 'svc_external-skip_manual' => $conf->exists('svc_external-skip_manual'), -% 'legacy_link' => $conf->exists('legacy_link'), -% +% 'bgcolor' => $bgcolor, +% 'cust_pkg' => $cust_pkg, +% 'part_pkg' => $cust_pkg->part_pkg, +% %conf_opt, % ); @@ -193,6 +111,7 @@ Current packages if ( el ) el.scrollIntoView(true); % } + <%init> my( $cust_main ) = @_; @@ -205,6 +124,23 @@ my $packages = get_packages($cust_main, $conf); my $show_location = $conf->exists('cust_pkg-always_show_location') || ( grep $_->locationnum, @$packages ); # ? '1' : '0'; +my $countrydefault = scalar($conf->config('countrydefault')) || 'US'; +my %conf_opt = ( + #for services.html and status.html + 'cust_pkg-display_times' => $conf->exists('cust_pkg-display_times'), + + #for status.html + 'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'), + + #for location.html + 'countrydefault' => $countrydefault, + 'statedefault' => ( scalar($conf->config('statedefault')) + || ($countrydefault eq 'US' ? 'CA' : '') ), + #for services.html + 'svc_external-skip_manual' => $conf->exists('svc_external-skip_manual'), + 'legacy_link' => $conf->exists('legacy_link'), +); + #subroutines sub get_packages { @@ -226,16 +162,4 @@ sub get_packages { [ $cust_main->$method() ]; } -sub order_pkg_link { - include( '/elements/popup_link-cust_main.html', - 'action' => $p. 'misc/order_pkg.html', - 'label' => 'Order new package', - 'actionlabel' => 'Order new package', - 'color' => '#333399', - 'cust_main' => shift, - 'closetext' => 'Close', - 'width' => 763, - ) -} - diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html index 106137ba9..af407b0df 100644 --- a/httemplate/view/cust_main/packages/status.html +++ b/httemplate/view/cust_main/packages/status.html @@ -122,7 +122,7 @@ % % } % -% if ( $conf->exists('cust_pkg-show_autosuspend') ) { +% if ( $opt{'cust_pkg-show_autosuspend'} ) { % my $autosuspend = pkg_autosuspend_time( $cust_pkg ); % $cust_pkg->set('autosuspend', $autosuspend) if $autosuspend; % } @@ -170,8 +170,6 @@ my %opt = @_; -my $conf = new FS::Conf; - my $bgcolor = $opt{'bgcolor'}; my $cust_pkg = $opt{'cust_pkg'}; my $part_pkg = $opt{'part_pkg'}; -- cgit v1.2.1 From 067cd12b6efe596c4ee57e8c17f30639e86494a2 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2009 10:17:02 +0000 Subject: add "extra_param" option to qsearch for more realisitic profiling data, RT#5083 --- FS/FS/Record.pm | 68 ++++++++++++++++++++++++++++++++++--------------------- FS/FS/cust_pkg.pm | 23 ++++++++++--------- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 0e8275b72..7019cb99c 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -215,23 +215,24 @@ objects. The preferred usage is to pass a hash reference of named parameters: - my @records = qsearch( { - 'table' => 'table_name', - 'hashref' => { 'field' => 'value' - 'field' => { 'op' => '<', - 'value' => '420', - }, - }, - - #these are optional... - 'select' => '*', - 'extra_sql' => 'AND field ', - 'order_by' => 'ORDER BY something', - #'cache_obj' => '', #optional - 'addl_from' => 'LEFT JOIN othtable USING ( field )', - 'debug' => 1, - } - ); + @records = qsearch( { + 'table' => 'table_name', + 'hashref' => { 'field' => 'value' + 'field' => { 'op' => '<', + 'value' => '420', + }, + }, + + #these are optional... + 'select' => '*', + 'extra_sql' => 'AND field = ? AND intfield = ?', + 'extra_param' => [ 'value', [ 5, 'int' ] ], + 'order_by' => 'ORDER BY something', + #'cache_obj' => '', #optional + 'addl_from' => 'LEFT JOIN othtable USING ( field )', + 'debug' => 1, + } + ); Much code still uses old-style positional parameters, this is also probably fine in the common case where there are only two parameters: @@ -262,18 +263,20 @@ sub _is_fs_float { } sub qsearch { - my($stable, $record, $select, $extra_sql, $order_by, $cache, $addl_from ); + my($stable, $record, $cache ); + my( $select, $extra_sql, $extra_param, $order_by, $addl_from ); my $debug = ''; if ( ref($_[0]) ) { #hashref for now, eventually maybe accept a list too my $opt = shift; - $stable = $opt->{'table'} or die "table name is required"; - $record = $opt->{'hashref'} || {}; - $select = $opt->{'select'} || '*'; - $extra_sql = $opt->{'extra_sql'} || ''; - $order_by = $opt->{'order_by'} || ''; - $cache = $opt->{'cache_obj'} || ''; - $addl_from = $opt->{'addl_from'} || ''; - $debug = $opt->{'debug'} || ''; + $stable = $opt->{'table'} or die "table name is required"; + $record = $opt->{'hashref'} || {}; + $select = $opt->{'select'} || '*'; + $extra_sql = $opt->{'extra_sql'} || ''; + $extra_param = $opt->{'extra_param'} || []; + $order_by = $opt->{'order_by'} || ''; + $cache = $opt->{'cache_obj'} || ''; + $addl_from = $opt->{'addl_from'} || ''; + $debug = $opt->{'debug'} || ''; } else { ($stable, $record, $select, $extra_sql, $cache, $addl_from ) = @_; $select ||= '*'; @@ -359,6 +362,19 @@ sub qsearch { } + foreach my $param ( @$extra_param ) { + my $TYPE = SQL_VARCHAR; + my $value = $param; + if ( ref($param) ) { + $value = $param->[0]; + my $type = $param->[1]; + if ( $type =~ /(big)?(int|serial)/i && $value =~ /^\d+(\.\d+)?$/ ) { + $TYPE = SQL_INTEGER; + } # & DECIMAL? well, who cares for now + } + $sth->bind_param($bind++, $value, { TYPE => $TYPE } ); + } + # $sth->execute( map $record->{$_}, # grep defined( $record->{$_} ) && $record->{$_} ne '', @fields # ) or croak "Error executing \"$statement\": ". $sth->errstr; diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index f2c3cccf5..8d4e0bf70 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1583,17 +1583,18 @@ sub extra_part_svc { qsearch( { 'table' => 'part_svc', 'hashref' => {}, - 'extra_sql' => "WHERE 0 = ( SELECT COUNT(*) FROM pkg_svc - WHERE pkg_svc.svcpart = part_svc.svcpart - AND pkg_svc.pkgpart = $pkgpart - AND quantity > 0 - ) - AND 0 < ( SELECT count(*) - FROM cust_svc - LEFT JOIN cust_pkg using ( pkgnum ) - WHERE cust_svc.svcpart = part_svc.svcpart - AND pkgnum = $pkgnum - )", + 'extra_sql' => + "WHERE 0 = ( SELECT COUNT(*) FROM pkg_svc + WHERE pkg_svc.svcpart = part_svc.svcpart + AND pkg_svc.pkgpart = ? + AND quantity > 0 + ) + AND 0 < ( SELECT COUNT(*) FROM cust_svc + LEFT JOIN cust_pkg using ( pkgnum ) + WHERE cust_svc.svcpart = part_svc.svcpart + AND pkgnum = ? + )", + 'extra_param' => [ [$self->pkgpart=>'int'], [$self->pkgnum=>'int'] ], } ); } -- cgit v1.2.1 From 3a1f501e679daa106fa4fe826ad70608bb033f54 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2009 10:34:20 +0000 Subject: avoid looking up package details redundantly in the pkg loop, RT#5083 --- httemplate/view/cust_main/packages/package.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html index b07e1af94..c56fa0bdc 100644 --- a/httemplate/view/cust_main/packages/package.html +++ b/httemplate/view/cust_main/packages/package.html @@ -58,18 +58,18 @@ % my $editi = $curuser->access_right('Edit customer package invoice details'); % my $editc = $curuser->access_right('Edit customer package comments'); +% my @cust_pkg_detail = $cust_pkg->cust_pkg_detail; +% my @invoice_detail = grep { $_->detailtype eq 'I' } @cust_pkg_detail; +% my @comments = grep { $_->detailtype eq 'C' } @cust_pkg_detail; % -% if ( $cust_pkg->cust_pkg_detail('I') -% || $cust_pkg->cust_pkg_detail('C') -% || $editi -% || $editc ) { +% if ( scalar(@invoice_detail) || scalar(@comments) || $editi || $editc ) { % % my $editlink = $p. 'edit/cust_pkg_detail?pkgnum='. $cust_pkg->pkgnum. % ';detailtype=';
-% if ( $cust_pkg->cust_pkg_detail('I') ) { +% if ( @invoice_detail ) { @@ -89,7 +89,7 @@ -% foreach my $cust_pkg_detail ( $cust_pkg->cust_pkg_detail('I') ) { +% foreach my $cust_pkg_detail ( @invoice_detail ) { @@ -113,7 +113,7 @@ % } -% if ( $cust_pkg->cust_pkg_detail('C') ) { +% if ( @comments ) { @@ -133,7 +133,7 @@ -% foreach my $cust_pkg_detail ( $cust_pkg->cust_pkg_detail('C') ) { +% foreach my $cust_pkg_detail ( @comments ) { -- cgit v1.2.1 From 77d3d252f8e577de62f0bd5d6d267bc2fd2e5278 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2009 10:39:57 +0000 Subject: avoid looking up part_pkg redundantly in the pkg loop, RT#5083 --- httemplate/view/cust_main/packages/package.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html index c56fa0bdc..5edbb4d59 100644 --- a/httemplate/view/cust_main/packages/package.html +++ b/httemplate/view/cust_main/packages/package.html @@ -38,7 +38,7 @@ % % if ( $curuser->access_right('Customize customer package') ) { % $br=1; - ( <%pkg_customize_link($cust_pkg,$cust_pkg->custnum)%> ) + ( <%pkg_customize_link($cust_pkg,$part_pkg)%> ) % } % <% $br ? '
' : '' %> @@ -198,9 +198,10 @@ sub pkg_dates_link { pkg_link('edit/REAL_cust_pkg', 'Edit dates', @_ ); } sub pkg_customize_link { my $cust_pkg = shift or return ''; + my $part_pkg = shift; my $custnum = $cust_pkg->custnum; qq!Customize!; } -- cgit v1.2.1 From 10bd4045596bc1daac97ce9d9ad706f696f8e4ab Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2009 11:52:22 +0000 Subject: seems to benchmark faster, RT#5083 --- FS/FS/cust_pkg.pm | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 8d4e0bf70..f2e0005d7 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1580,20 +1580,37 @@ sub extra_part_svc { my $pkgnum = $self->pkgnum; my $pkgpart = $self->pkgpart; +# qsearch( { +# 'table' => 'part_svc', +# 'hashref' => {}, +# 'extra_sql' => +# "WHERE 0 = ( SELECT COUNT(*) FROM pkg_svc +# WHERE pkg_svc.svcpart = part_svc.svcpart +# AND pkg_svc.pkgpart = ? +# AND quantity > 0 +# ) +# AND 0 < ( SELECT COUNT(*) FROM cust_svc +# LEFT JOIN cust_pkg USING ( pkgnum ) +# WHERE cust_svc.svcpart = part_svc.svcpart +# AND pkgnum = ? +# )", +# 'extra_param' => [ [$self->pkgpart=>'int'], [$self->pkgnum=>'int'] ], +# } ); + +#seems to benchmark slightly faster... qsearch( { - 'table' => 'part_svc', - 'hashref' => {}, - 'extra_sql' => - "WHERE 0 = ( SELECT COUNT(*) FROM pkg_svc - WHERE pkg_svc.svcpart = part_svc.svcpart - AND pkg_svc.pkgpart = ? - AND quantity > 0 - ) - AND 0 < ( SELECT COUNT(*) FROM cust_svc - LEFT JOIN cust_pkg using ( pkgnum ) - WHERE cust_svc.svcpart = part_svc.svcpart - AND pkgnum = ? - )", + 'select' => 'DISTINCT ON (svcpart) part_svc.*', + 'table' => 'part_svc', + 'addl_from' => + 'LEFT JOIN pkg_svc ON ( pkg_svc.svcpart = part_svc.svcpart + AND pkg_svc.pkgpart = ? + AND quantity > 0 + ) + LEFT JOIN cust_svc ON ( cust_svc.svcpart = part_svc.svcpart ) + LEFT JOIN cust_pkg USING ( pkgnum ) + ', + 'hashref' => {}, + 'extra_sql' => "WHERE pkgsvcnum IS NULL AND cust_pkg.pkgnum = ? ", 'extra_param' => [ [$self->pkgpart=>'int'], [$self->pkgnum=>'int'] ], } ); } -- cgit v1.2.1 From 35e195cdee48f99ca9b6406491696c7cdccb7814 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2009 11:56:11 +0000 Subject: index pkg_svc.quantity, RT#5083 --- FS/FS/Schema.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 745cf674b..59abbda8a 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1233,7 +1233,7 @@ sub tables_hashref { ], 'primary_key' => 'pkgsvcnum', 'unique' => [ ['pkgpart', 'svcpart'] ], - 'index' => [ ['pkgpart'] ], + 'index' => [ ['pkgpart'], ['quantity'] ], }, 'part_referral' => { -- cgit v1.2.1 From 75989a32bd20f0ab3d38d2cd2c05795ea9b7590d Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 29 Mar 2009 23:44:12 +0000 Subject: hide over 2 (or configured) cancelled and one-time charge packages, RT#5083 --- FS/FS/Conf.pm | 7 +++++++ httemplate/view/cust_main/packages.html | 33 +++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index b6fea5413..17da9def9 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2197,6 +2197,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'text', }, + { + 'key' => 'cust_main-packages-years', + 'section' => 'UI', + 'description' => 'Number of years to show old (cancelled and one-time charge) packages by default. Currently defaults to 2.', + 'type' => 'text', + }, + { 'key' => 'cust_main-use_comments', 'section' => 'UI', diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 72846b8ec..7643e3efd 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -53,6 +53,13 @@ Current packages cancelled packages ) % } +% if ( $num_old_packages ) { +% $cgi->param('showoldpackages', 1); + ( show old packages ) +% } elsif ( $cgi->param('showoldpackages') ) { +% $cgi->param('showoldpackages', 0); + ( hide old packages ) +% } % if ( @$packages ) { <% include('/elements/table-grid.html') %> @@ -119,7 +126,7 @@ my $conf = new FS::Conf; my $curuser = $FS::CurrentUser::CurrentUser; -my $packages = get_packages($cust_main, $conf); +my( $packages, $num_old_packages ) = get_packages($cust_main, $conf); my $show_location = $conf->exists('cust_pkg-always_show_location') || ( grep $_->locationnum, @$packages ); # ? '1' : '0'; @@ -146,8 +153,7 @@ my %conf_opt = ( sub get_packages { my $cust_main = shift or return undef; my $conf = shift; - - my @packages = (); + my $method; if ( $cgi->param('showcancelledpackages') eq '0' #see if it was set by me || ( $conf->exists('hidecancelledpackages') @@ -159,7 +165,26 @@ sub get_packages { $method = 'all_pkgs'; } - [ $cust_main->$method() ]; + my @packages = $cust_main->$method(); + my $num_old_packages = scalar(@packages); + + unless ( $cgi->param('showoldpackages') ) { + my $years = $conf->config('cust_main-packages-years') || 2; + my $seconds = 31556926; #60*60*24*365.2422 is close enough + my $then = time - $seconds; + + my %hide = ( 'cancelled' => 'cancel', + 'one-time charge' => 'setup', + ); + + @packages = + grep { !exists($hide{$_->status}) or $_->get($hide{$_->status}) > $then } + @packages; + } + + $num_old_packages -= scalar(@packages); + + ( \@packages, $num_old_packages ); } -- cgit v1.2.1 From 3b5ccffae54e59c012eb1ebb348207510ca1d5ce Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 00:32:03 +0000 Subject: part_pkg caching should speedup display of lots of packages, RT#5083 --- FS/FS/cust_pkg.pm | 2 ++ httemplate/view/cust_main/packages.html | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index f2e0005d7..44e1210fe 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1220,8 +1220,10 @@ L). =cut +use Carp qw(cluck); sub part_pkg { my $self = shift; + cluck "part_pkg called" if $DEBUG > 1 && ! $self->{'_pkgpart'}; #exists( $self->{'_pkgpart'} ) $self->{'_pkgpart'} ? $self->{'_pkgpart'} diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 7643e3efd..9b1d5b317 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -76,6 +76,7 @@ Current packages
+% my %part_pkg = (); % foreach my $cust_pkg (@$packages) { % % if ( $bgcolor eq $bgcolor1 ) { @@ -84,12 +85,18 @@ Current packages % $bgcolor = $bgcolor1; % } % +% $part_pkg{$cust_pkg->pkgpart} ||= $cust_pkg->part_pkg; +% $cust_pkg->{'_pkgpart'} ||= $part_pkg{$cust_pkg->pkgpart}; #XXX cache kludge +% % my %iopt = ( % 'bgcolor' => $bgcolor, % 'cust_pkg' => $cust_pkg, -% 'part_pkg' => $cust_pkg->part_pkg, +% 'part_pkg' => $part_pkg{$cust_pkg->pkgpart}, % %conf_opt, % ); +% +% my $oldDEBUG = $FS::cust_pkg::DEBUG; +% $FS::cust_pkg::DEBUG = 2; @@ -101,6 +108,8 @@ Current packages <% include('packages/services.html', %iopt) %> +% $FS::cust_pkg::DEBUG = $oldDEBUG; + % }
Exp.Exp.
CVV2CVV2 (help)
Exact name on cardExact name on card
Card billing address - -
Address line 2 - -
City - - - - - - - - -
- - State - - Zip - -
-
+ <% $conf->exists($i->key, $agentnum) + ? '' + : 'empty' + %> +
+ <% $conf->exists($i->key, $agentnum) + ? qq!download! + : '' + %> +
+ <% $conf->exists($i->key, $agentnum) + ? qq!download! + : 'empty' + %> +
GECOSReal Name
Package Class + <% include('/elements/select-cust-pkg_class.html', + 'curr_value' => $opt{'classnum'}, + 'pkg_class' => \@pkg_class, + 'onchange' => 'classnum_changed', + ) + %> +
Package + <% include('/elements/select-cust-part_pkg.html', + 'curr_value' => $opt{'curr_value'}, #$pkgpart + 'classnum' => $opt{'classnum'}, + 'cust_main' => $opt{'cust_main'}, #$cust_main + 'onchange' => 'enable_order_pkg', + ) + %> +
<% $opt{'label'} || 'Packages' %> <% include( '/elements/select-table.html', - 'table' => 'part_pkg', - 'name_col' => 'pkg', - 'value' => '', - 'empty_label' => '(none)', - 'element_etc' => 'multiple', + 'table' => 'part_pkg', + 'name_col' => 'pkg', + 'disable_empty' => 1, + 'element_etc' => 'multiple', %opt, ) %> diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi index c4dfca200..16b707121 100755 --- a/httemplate/misc/change_pkg.cgi +++ b/httemplate/misc/change_pkg.cgi @@ -13,19 +13,15 @@ <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><% $part_pkg->pkg |h %> - <% $part_pkg->comment |h %>
New package - <% include('/elements/select-cust-part_pkg.html', - 'cust_main' => $cust_main, - 'element_name' => 'pkgpart', - #'extra_sql' => ' AND pkgpart != '. $cust_pkg->pkgpart, - 'curr_value' => scalar($cgi->param('pkgpart')), - ) - %> -
Package - <% include('/elements/select-cust-part_pkg.html', - 'curr_value' => $pkgpart, - 'cust_main' => $cust_main, - 'onchange' => 'enable_order_pkg', - ) - %> -
<% include('/elements/table-grid.html') %>
 - <% $cust_pkg_detail->detail |h %>
<% include('/elements/table-grid.html') %>
 - <% $cust_pkg_detail->detail |h %>
Services
-- cgit v1.2.1 From 4a525836ffb9fa8a941c11247637543d931733b8 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 01:05:04 +0000 Subject: forget caching, instead scoop up cust_pkg and part_pkg in one query, RT#5083 --- FS/FS/cust_main.pm | 31 +++++++++++++++++-------------- httemplate/view/cust_main/packages.html | 16 +++++++--------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 73cf826ab..1766b4542 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1809,7 +1809,7 @@ sub has_ship_address { scalar( grep { $self->getfield("ship_$_") ne '' } $self->addr_fields ); } -=item all_pkgs +=item all_pkgs [ EXTRA_QSEARCH_PARAMS_HASHREF ] Returns all packages (see L) for this customer. @@ -1817,14 +1817,19 @@ Returns all packages (see L) for this customer. sub all_pkgs { my $self = shift; + my $extra_qsearch = ref($_[0]) ? shift : {}; - return $self->num_pkgs unless wantarray; + return $self->num_pkgs unless wantarray; #XXX doesn't work w/$extra_qsearch my @cust_pkg = (); if ( $self->{'_pkgnum'} ) { @cust_pkg = values %{ $self->{'_pkgnum'}->cache }; } else { - @cust_pkg = qsearch( 'cust_pkg', { 'custnum' => $self->custnum }); + @cust_pkg = qsearch({ + %$extra_qsearch, + 'table' => 'cust_pkg', + 'hashref' => { 'custnum' => $self->custnum }, + }); } sort sort_packages @cust_pkg; @@ -1851,7 +1856,7 @@ sub cust_location { qsearch('cust_location', { 'custnum' => $self->custnum } ); } -=item ncancelled_pkgs +=item ncancelled_pkgs [ EXTRA_QSEARCH_PARAMS_HASHREF ] Returns all non-cancelled packages (see L) for this customer. @@ -1859,6 +1864,7 @@ Returns all non-cancelled packages (see L) for this customer. sub ncancelled_pkgs { my $self = shift; + my $extra_qsearch = ref($_[0]) ? shift : {}; return $self->num_ncancelled_pkgs unless wantarray; @@ -1877,16 +1883,13 @@ sub ncancelled_pkgs { $self->custnum. "\n" if $DEBUG > 1; - @cust_pkg = - qsearch( 'cust_pkg', { - 'custnum' => $self->custnum, - 'cancel' => '', - }); - push @cust_pkg, - qsearch( 'cust_pkg', { - 'custnum' => $self->custnum, - 'cancel' => 0, - }); + @cust_pkg = qsearch({ + %$extra_qsearch, + 'table' => 'cust_pkg', + 'hashref' => { 'custnum' => $self->custnum }, + 'extra_sql' => ' AND ( cancel IS NULL OR cancel = 0 ) ', + }); + } sort sort_packages @cust_pkg; diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 9b1d5b317..56bc63fd0 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -76,7 +76,7 @@ Current packages
Services
@@ -174,7 +169,10 @@ sub get_packages { $method = 'all_pkgs'; } - my @packages = $cust_main->$method(); + my @packages = $cust_main->$method( { + 'select' => 'cust_pkg.*, part_pkg.*', + 'addl_from' => 'LEFT JOIN part_pkg USING ( pkgpart )' + } ); my $num_old_packages = scalar(@packages); unless ( $cgi->param('showoldpackages') ) { -- cgit v1.2.1 From a852ab2648b1496a0010276c2e3b516211190671 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 01:09:01 +0000 Subject: forget caching, instead scoop up cust_pkg and part_pkg in one query, RT#5083 --- httemplate/view/cust_main/packages.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 56bc63fd0..07601dd54 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -76,7 +76,7 @@ Current packages Services -% local($FS::cust_pkg::DEBUG) = 2; +% $FS::cust_pkg::DEBUG = 2; % foreach my $cust_pkg (@$packages) { % % if ( $bgcolor eq $bgcolor1 ) { -- cgit v1.2.1 From c9ac50fa78dcf1f9ac3dda747448ee8ef703d69c Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 01:28:40 +0000 Subject: fix setup date display, RT#5083 --- httemplate/view/cust_main/packages.html | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 07601dd54..8ff2269ab 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -85,6 +85,9 @@ Current packages % $bgcolor = $bgcolor1; % } % +% my %hash = $cust_pkg->hash; +% my %part_pkg = map { /^part_pkg_(.+)$/ or die; $1 => $hash{$_}; } +% grep { /^part_pkg_/ } keys %hash; % $cust_pkg->{'_pkgpart'} = new FS::part_pkg { $cust_pkg->hash }; #quelle klud % % my %iopt = ( @@ -169,8 +172,12 @@ sub get_packages { $method = 'all_pkgs'; } + my $part_pkg_fields = join(', ', map { "part_pkg.$_ AS part_pkg_$_" } + fields('part_pkg') + ); + my @packages = $cust_main->$method( { - 'select' => 'cust_pkg.*, part_pkg.*', + 'select' => "cust_pkg.*, $part_pkg_fields", 'addl_from' => 'LEFT JOIN part_pkg USING ( pkgpart )' } ); my $num_old_packages = scalar(@packages); -- cgit v1.2.1 From ff2ad3e74efe8173d362003e1efdce5953388acf Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 01:39:26 +0000 Subject: doh, fix pkg display, RT#5083 --- httemplate/view/cust_main/packages.html | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 8ff2269ab..9b13a8f97 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -86,9 +86,9 @@ Current packages % } % % my %hash = $cust_pkg->hash; -% my %part_pkg = map { /^part_pkg_(.+)$/ or die; $1 => $hash{$_}; } +% my %part_pkg = map { /^part_pkg_(.+)$/ or die; ( $1 => $hash{$_} ); } % grep { /^part_pkg_/ } keys %hash; -% $cust_pkg->{'_pkgpart'} = new FS::part_pkg { $cust_pkg->hash }; #quelle klud +% $cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg; % % my %iopt = ( % 'bgcolor' => $bgcolor, @@ -172,12 +172,14 @@ sub get_packages { $method = 'all_pkgs'; } - my $part_pkg_fields = join(', ', map { "part_pkg.$_ AS part_pkg_$_" } - fields('part_pkg') - ); + my $cust_pkg_fields = + join(', ', map { "cust_pkg.$_ AS $_" } fields('cust_pkg') ); + + my $part_pkg_fields = + join(', ', map { "part_pkg.$_ AS part_pkg_$_" } fields('part_pkg') ); my @packages = $cust_main->$method( { - 'select' => "cust_pkg.*, $part_pkg_fields", + 'select' => "$cust_pkg_fields, $part_pkg_fields", 'addl_from' => 'LEFT JOIN part_pkg USING ( pkgpart )' } ); my $num_old_packages = scalar(@packages); -- cgit v1.2.1 From 77df77ea5cc49c10d8768d25d54332dc0833466e Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 03:12:25 +0000 Subject: really prevent separate part_pkg query, RT#5083 --- httemplate/view/cust_main/packages.html | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 9b13a8f97..001e6ec82 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -85,11 +85,6 @@ Current packages % $bgcolor = $bgcolor1; % } % -% my %hash = $cust_pkg->hash; -% my %part_pkg = map { /^part_pkg_(.+)$/ or die; ( $1 => $hash{$_} ); } -% grep { /^part_pkg_/ } keys %hash; -% $cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg; -% % my %iopt = ( % 'bgcolor' => $bgcolor, % 'cust_pkg' => $cust_pkg, @@ -184,6 +179,13 @@ sub get_packages { } ); my $num_old_packages = scalar(@packages); + foreach my $cust_pkg ( @packages ) { + my %hash = $cust_pkg->hash; + my %part_pkg = map { /^part_pkg_(.+)$/ or die; ( $1 => $hash{$_} ); } + grep { /^part_pkg_/ } keys %hash; + $cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg; + } + unless ( $cgi->param('showoldpackages') ) { my $years = $conf->config('cust_main-packages-years') || 2; my $seconds = 31556926; #60*60*24*365.2422 is close enough -- cgit v1.2.1 From c13fb7ce1d8cba28ae0d56802b71856b0b7995ea Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 03:47:13 +0000 Subject: didn't need this, but more future-proof, RT#5083 --- FS/FS/cust_main.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 1766b4542..256eb732f 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1883,11 +1883,12 @@ sub ncancelled_pkgs { $self->custnum. "\n" if $DEBUG > 1; + $extra_qsearch->{'extra_sql'} .= ' AND ( cancel IS NULL OR cancel = 0 ) '; + @cust_pkg = qsearch({ %$extra_qsearch, 'table' => 'cust_pkg', 'hashref' => { 'custnum' => $self->custnum }, - 'extra_sql' => ' AND ( cancel IS NULL OR cancel = 0 ) ', }); } -- cgit v1.2.1 From 613f320ae076de8612ff80fc99c516b544ff3897 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 04:15:56 +0000 Subject: try not to search for nothing in cust_svc so much, RT#5083 --- FS/FS/cust_pkg.pm | 29 +++++++++++++++++++---------- httemplate/view/cust_main/packages.html | 12 ++++++++++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 44e1210fe..78f4bedb9 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -2,6 +2,7 @@ package FS::cust_pkg; use strict; use vars qw(@ISA $disable_agentcheck $DEBUG); +use Carp qw(cluck); use Scalar::Util qw( blessed ); use List::Util qw(max); use Tie::IxHash; @@ -1220,14 +1221,11 @@ L). =cut -use Carp qw(cluck); sub part_pkg { my $self = shift; - cluck "part_pkg called" if $DEBUG > 1 && ! $self->{'_pkgpart'}; - #exists( $self->{'_pkgpart'} ) - $self->{'_pkgpart'} - ? $self->{'_pkgpart'} - : qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } ); + return $self->{'_pkgpart'} if $self->{'_pkgpart'}; + cluck "cust_pkg->part_pkg called" if $DEBUG > 1; + qsearchs( 'part_pkg', { 'pkgpart' => $self->pkgpart } ); } =item old_cust_pkg @@ -1417,6 +1415,8 @@ services. sub cust_svc { my $self = shift; + cluck "cust_pkg->cust_svc called" if $DEBUG > 1; + if ( @_ ) { return qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum, 'svcpart' => shift, } ); @@ -1442,7 +1442,8 @@ is specified, return only the matching services. sub overlimit { my $self = shift; - grep { $_->overlimit } $self->cust_svc; + return () unless $self->num_cust_svc(@_); + grep { $_->overlimit } $self->cust_svc(@_); } =item h_cust_svc END_TIMESTAMP [ START_TIMESTAMP ] @@ -1491,9 +1492,15 @@ specified, counts only the matching services. sub num_cust_svc { my $self = shift; + + return $self->{'_num_cust_svc'} + if !@_ && exists($self->{'_num_cust_svc'}) + && $self->{'_num_cust_svc'} =~ /\d/; + my $sql = 'SELECT COUNT(*) FROM cust_svc WHERE pkgnum = ?'; $sql .= ' AND svcpart = ?' if @_; - my $sth = dbh->prepare($sql) or die dbh->errstr; + + my $sth = dbh->prepare($sql) or die dbh->errstr; $sth->execute($self->pkgnum, @_) or die $sth->errstr; $sth->fetchrow_arrayref->[0]; } @@ -1550,7 +1557,8 @@ sub part_svc { $part_svc->{'Hash'}{'num_cust_svc'} = $num_cust_svc; #more evil $part_svc->{'Hash'}{'num_avail'} = max( 0, $pkg_svc->quantity - $num_cust_svc ); - $part_svc->{'Hash'}{'cust_pkg_svc'} = [ $self->cust_svc($part_svc->svcpart) ]; + $part_svc->{'Hash'}{'cust_pkg_svc'} = + $num_cust_svc ? [ $self->cust_svc($part_svc->svcpart) ] : []; $part_svc; } $self->part_pkg->pkg_svc; @@ -1560,7 +1568,8 @@ sub part_svc { my $num_cust_svc = $self->num_cust_svc($part_svc->svcpart); $part_svc->{'Hash'}{'num_cust_svc'} = $num_cust_svc; #speak no evail $part_svc->{'Hash'}{'num_avail'} = 0; #0-$num_cust_svc ? - $part_svc->{'Hash'}{'cust_pkg_svc'} = [ $self->cust_svc($part_svc->svcpart) ]; + $part_svc->{'Hash'}{'cust_pkg_svc'} = + $num_cust_svc ? [ $self->cust_svc($part_svc->svcpart) ] : []; $part_svc; } $self->extra_part_svc; diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 001e6ec82..d98de8e63 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -173,9 +173,17 @@ sub get_packages { my $part_pkg_fields = join(', ', map { "part_pkg.$_ AS part_pkg_$_" } fields('part_pkg') ); + my $group_by = + join(', ', map "cust_pkg.$_", fields('cust_pkg') ). ', '. + join(', ', map "part_pkg.$_", fields('part_pkg') ); + + my $num_cust_svc = + '( SELECT COUNT(*) FROM cust_svc WHERE cust_pkg.pkgnum = cust_svc.svcnum )'; + my @packages = $cust_main->$method( { - 'select' => "$cust_pkg_fields, $part_pkg_fields", - 'addl_from' => 'LEFT JOIN part_pkg USING ( pkgpart )' + 'select' => " $cust_pkg_fields, $part_pkg_fields, ". + " $num_cust_svc AS num_cust_svc ", + 'addl_from' => ' LEFT JOIN part_pkg USING ( pkgpart ) ', } ); my $num_old_packages = scalar(@packages); -- cgit v1.2.1 From 5ef6e82fad107523eae428d3fea51e2302c99cb6 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 04:31:47 +0000 Subject: try not to search for nothing in cust_svc so much, RT#5083 --- httemplate/view/cust_main/packages.html | 1 + 1 file changed, 1 insertion(+) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index d98de8e63..20d42a48e 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -192,6 +192,7 @@ sub get_packages { my %part_pkg = map { /^part_pkg_(.+)$/ or die; ( $1 => $hash{$_} ); } grep { /^part_pkg_/ } keys %hash; $cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg; + $cust_pkg->{'_num_cust_svc'} = $cust_pkg->get('_num_cust_svc'); } unless ( $cgi->param('showoldpackages') ) { -- cgit v1.2.1 From dbd43e72a0cc7510f344b133c8f0b6ac8dd07c51 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 04:35:39 +0000 Subject: doh! underscore, RT#5083 --- httemplate/view/cust_main/packages.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 20d42a48e..aa1d7e721 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -192,7 +192,7 @@ sub get_packages { my %part_pkg = map { /^part_pkg_(.+)$/ or die; ( $1 => $hash{$_} ); } grep { /^part_pkg_/ } keys %hash; $cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg; - $cust_pkg->{'_num_cust_svc'} = $cust_pkg->get('_num_cust_svc'); + $cust_pkg->{'_num_cust_svc'} = $cust_pkg->get('num_cust_svc'); } unless ( $cgi->param('showoldpackages') ) { -- cgit v1.2.1 From 631063078b0e9ac6d53616f42c32eec30a76d24b Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 04:41:33 +0000 Subject: double doh! RT#5083 --- httemplate/view/cust_main/packages.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index aa1d7e721..53ed6bf2b 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -178,7 +178,7 @@ sub get_packages { join(', ', map "part_pkg.$_", fields('part_pkg') ); my $num_cust_svc = - '( SELECT COUNT(*) FROM cust_svc WHERE cust_pkg.pkgnum = cust_svc.svcnum )'; + '( SELECT COUNT(*) FROM cust_svc WHERE cust_pkg.pkgnum = cust_svc.pkgnum )'; my @packages = $cust_main->$method( { 'select' => " $cust_pkg_fields, $part_pkg_fields, ". -- cgit v1.2.1 From 259747e66fcb16f3b84bf4a0e9673517f4ccd1d2 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 04:50:13 +0000 Subject: and hopefully actually using the count will finally do it, RT#5083 --- FS/FS/cust_pkg.pm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 78f4bedb9..86ce25566 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1415,13 +1415,15 @@ services. sub cust_svc { my $self = shift; - cluck "cust_pkg->cust_svc called" if $DEBUG > 1; - if ( @_ ) { return qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum, 'svcpart' => shift, } ); } + return () unless $self->num_cust_svc; + + cluck "cust_pkg->cust_svc called" if $DEBUG > 1; + #if ( $self->{'_svcnum'} ) { # values %{ $self->{'_svcnum'}->cache }; #} else { -- cgit v1.2.1 From 5a66188aae7af4c05345c358f181b523fb2270fa Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 05:08:53 +0000 Subject: and hopefully actually using the count will finally do it, RT#5083 --- FS/FS/cust_pkg.pm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 86ce25566..348b1e498 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1415,14 +1415,14 @@ services. sub cust_svc { my $self = shift; + return () unless $self->num_cust_svc(@_); + if ( @_ ) { return qsearch( 'cust_svc', { 'pkgnum' => $self->pkgnum, 'svcpart' => shift, } ); } - return () unless $self->num_cust_svc; - - cluck "cust_pkg->cust_svc called" if $DEBUG > 1; + cluck "cust_pkg->cust_svc called" if $DEBUG > 2; #if ( $self->{'_svcnum'} ) { # values %{ $self->{'_svcnum'}->cache }; @@ -1496,8 +1496,9 @@ sub num_cust_svc { my $self = shift; return $self->{'_num_cust_svc'} - if !@_ && exists($self->{'_num_cust_svc'}) - && $self->{'_num_cust_svc'} =~ /\d/; + if !scalar(@_) + && exists($self->{'_num_cust_svc'}) + && $self->{'_num_cust_svc'} =~ /\d/; my $sql = 'SELECT COUNT(*) FROM cust_svc WHERE pkgnum = ?'; $sql .= ' AND svcpart = ?' if @_; -- cgit v1.2.1 From cec41a47c4cbb9eda007713e376970addc9ac626 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 30 Mar 2009 06:10:18 +0000 Subject: okay. counts are needed for the package sort, so push the embedded counting into cust_main.pm. sure hope this does it. RT#5083 --- FS/FS/cust_main.pm | 43 ++++++++++++++++++++++----------- FS/FS/cust_pkg.pm | 3 +++ httemplate/view/cust_main/packages.html | 9 ++----- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 256eb732f..cc399838e 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1819,17 +1819,13 @@ sub all_pkgs { my $self = shift; my $extra_qsearch = ref($_[0]) ? shift : {}; - return $self->num_pkgs unless wantarray; #XXX doesn't work w/$extra_qsearch + return $self->num_pkgs unless wantarray || keys(%$extra_qsearch); my @cust_pkg = (); if ( $self->{'_pkgnum'} ) { @cust_pkg = values %{ $self->{'_pkgnum'}->cache }; } else { - @cust_pkg = qsearch({ - %$extra_qsearch, - 'table' => 'cust_pkg', - 'hashref' => { 'custnum' => $self->custnum }, - }); + @cust_pkg = $self->_cust_pkg($extra_qsearch); } sort sort_packages @cust_pkg; @@ -1885,11 +1881,7 @@ sub ncancelled_pkgs { $extra_qsearch->{'extra_sql'} .= ' AND ( cancel IS NULL OR cancel = 0 ) '; - @cust_pkg = qsearch({ - %$extra_qsearch, - 'table' => 'cust_pkg', - 'hashref' => { 'custnum' => $self->custnum }, - }); + @cust_pkg = $self->_cust_pkg($extra_qsearch); } @@ -1897,6 +1889,27 @@ sub ncancelled_pkgs { } +sub _cust_pkg { + my $self = shift; + my $extra_qsearch = ref($_[0]) ? shift : {}; + + $extra_qsearch->{'select'} ||= '*'; + $extra_qsearch->{'select'} .= + ',( SELECT COUNT(*) FROM cust_svc WHERE cust_pkg.pkgnum = cust_svc.pkgnum ) + AS _num_cust_svc'; + + map { + $_->{'_num_cust_svc'} = $_->get('_num_cust_svc'); + $_; + } + qsearch({ + %$extra_qsearch, + 'table' => 'cust_pkg', + 'hashref' => { 'custnum' => $self->custnum }, + }); + +} + # This should be generalized to use config options to determine order. sub sort_packages { @@ -1906,11 +1919,13 @@ sub sort_packages { #shouldn't get here... return 0; } else { + my $a_num_cust_svc = $a->num_cust_svc; + my $b_num_cust_svc = $b->num_cust_svc; + return 0 if !$a_num_cust_svc && !$b_num_cust_svc; + return -1 if $a_num_cust_svc && !$b_num_cust_svc; + return 1 if !$a_num_cust_svc && $b_num_cust_svc; my @a_cust_svc = $a->cust_svc; my @b_cust_svc = $b->cust_svc; - return 0 if !scalar(@a_cust_svc) && !scalar(@b_cust_svc); - return -1 if scalar(@a_cust_svc) && !scalar(@b_cust_svc); - return 1 if !scalar(@a_cust_svc) && scalar(@b_cust_svc); $a_cust_svc[0]->svc_x->label cmp $b_cust_svc[0]->svc_x->label; } diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 348b1e498..902b1d325 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1500,6 +1500,9 @@ sub num_cust_svc { && exists($self->{'_num_cust_svc'}) && $self->{'_num_cust_svc'} =~ /\d/; + cluck "cust_pkg->num_cust_svc called, _num_cust_svc:".$self->{'_num_cust_svc'} + if $DEBUG > 2; + my $sql = 'SELECT COUNT(*) FROM cust_svc WHERE pkgnum = ?'; $sql .= ' AND svcpart = ?' if @_; diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 53ed6bf2b..d55560f34 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -177,13 +177,9 @@ sub get_packages { join(', ', map "cust_pkg.$_", fields('cust_pkg') ). ', '. join(', ', map "part_pkg.$_", fields('part_pkg') ); - my $num_cust_svc = - '( SELECT COUNT(*) FROM cust_svc WHERE cust_pkg.pkgnum = cust_svc.pkgnum )'; - my @packages = $cust_main->$method( { - 'select' => " $cust_pkg_fields, $part_pkg_fields, ". - " $num_cust_svc AS num_cust_svc ", - 'addl_from' => ' LEFT JOIN part_pkg USING ( pkgpart ) ', + 'select' => "$cust_pkg_fields, $part_pkg_fields", + 'addl_from' => 'LEFT JOIN part_pkg USING ( pkgpart )', } ); my $num_old_packages = scalar(@packages); @@ -192,7 +188,6 @@ sub get_packages { my %part_pkg = map { /^part_pkg_(.+)$/ or die; ( $1 => $hash{$_} ); } grep { /^part_pkg_/ } keys %hash; $cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg; - $cust_pkg->{'_num_cust_svc'} = $cust_pkg->get('num_cust_svc'); } unless ( $cgi->param('showoldpackages') ) { -- cgit v1.2.1 From c46d0f3d030f71a21a6d459100b29d7454f8627b Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 30 Mar 2009 16:33:44 +0000 Subject: schema and module should agree on column names --- FS/FS/cust_tax_location.pm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/FS/FS/cust_tax_location.pm b/FS/FS/cust_tax_location.pm index b7437a08b..7c6989c65 100644 --- a/FS/FS/cust_tax_location.pm +++ b/FS/FS/cust_tax_location.pm @@ -119,7 +119,7 @@ sub check { || $self->ut_text('state') || $self->ut_numbern('plus4hi') || $self->ut_numbern('plus4lo') - || $self->ut_enum('default', [ '', ' ', 'Y' ] ) # wtf? + || $self->ut_enum('default_location', [ '', 'Y' ] ) || $self->ut_enum('cityflag', [ '', 'I', 'O', 'B' ] ) || $self->ut_alpha('geocode') ; @@ -179,7 +179,7 @@ sub batch_import { } if ( $format eq 'cch' || $format eq 'cch-update' ) { - @fields = qw( zip state plus4lo plus4hi geocode default ); + @fields = qw( zip state plus4lo plus4hi geocode default_location ); push @fields, 'actionflag' if $format eq 'cch-update'; $imported++ if $format eq 'cch-update'; #empty file ok @@ -188,6 +188,7 @@ sub batch_import { my $hash = shift; $hash->{'data_vendor'} = 'cch'; + $hash->{'default_location'} =~ s/ //g; if (exists($hash->{actionflag}) && $hash->{actionflag} eq 'D') { delete($hash->{actionflag}); @@ -210,7 +211,7 @@ sub batch_import { }; } elsif ( $format eq 'cch-zip' || $format eq 'cch-update-zip' ) { - @fields = qw( zip city county state postalcity countyfips countydef default geocode cityflag unique ); + @fields = qw( zip city county state postalcity countyfips countydef default_location geocode cityflag unique ); push @fields, 'actionflag' if $format eq 'cch-update-zip'; $imported++ if $format eq 'cch-update'; #empty file ok @@ -222,6 +223,7 @@ sub batch_import { delete($hash->{$_}) foreach qw( countyfips countydef unique ); $hash->{'cityflag'} =~ s/ //g; + $hash->{'default_location'} =~ s/ //g; if (exists($hash->{actionflag}) && $hash->{actionflag} eq 'D') { delete($hash->{actionflag}); -- cgit v1.2.1 From 8d6784828998dc848eede30cef4a38bfd30fc3d1 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 31 Mar 2009 19:46:00 +0000 Subject: fix impending billing notification for Pg 8.3's more strict type checking --- FS/FS/Cron/notify.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Cron/notify.pm b/FS/FS/Cron/notify.pm index 23cf920b2..c67fcc19a 100644 --- a/FS/FS/Cron/notify.pm +++ b/FS/FS/Cron/notify.pm @@ -35,7 +35,7 @@ sub notify_flat_delay { and 0 < ( select count(*) from part_pkg_option where part_pkg.pkgpart = part_pkg_option.pkgpart and part_pkg_option.optionname = 'recur_notify' - and part_pkg_option.optionvalue > 0 + and CAST( part_pkg_option.optionvalue AS INTEGER ) > 0 and 0 <= ( $time + CAST( part_pkg_option.optionvalue AS $integer ) * 86400 -- cgit v1.2.1 From 432ab2af40034d4f63f7771eff6207c73b057959 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 31 Mar 2009 19:47:35 +0000 Subject: quiet warning: Argument "" isn't numeric in numeric eq (==) at /usr/local/share/perl/5.10.0/FS/part_pkg/voip_cdr.pm line 201 --- FS/FS/part_pkg/voip_cdr.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index a691fdad6..fe05b684a 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -199,7 +199,8 @@ sub calc_recur { my $last_bill = $cust_pkg->get('last_bill'); #->last_bill falls back to setup return 0 - if $self->option('recur_temporality', 1) eq 'preceding' && $last_bill == 0; + if $self->option('recur_temporality', 1) eq 'preceding' + && ( $last_bill eq '' || $last_bill == 0 ); my $ratenum = $cust_pkg->part_pkg->option('ratenum'); -- cgit v1.2.1 From 7889bec2b0f951c053b06ef45fbc60dacd3f8a88 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 31 Mar 2009 19:51:54 +0000 Subject: really fix notify for Pg 8.3 --- FS/FS/Cron/notify.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Cron/notify.pm b/FS/FS/Cron/notify.pm index c67fcc19a..5b0e186ad 100644 --- a/FS/FS/Cron/notify.pm +++ b/FS/FS/Cron/notify.pm @@ -62,7 +62,7 @@ END 0 = ( select count(*) from cust_pkg_option where cust_pkg.pkgnum = cust_pkg_option.pkgnum and cust_pkg_option.optionname = 'impending_recur_notification_sent' - and cust_pkg_option.optionvalue = 1 + and CAST( cust_pkg_option.optionvalue AS INTEGER ) = 1 ) END -- cgit v1.2.1 From 2b8f2f7d7c2fa79072f7404865691239f23fa5ba Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 1 Apr 2009 03:44:34 +0000 Subject: add options to skip CDRs under a defined length and with specific lastapp --- FS/FS/part_pkg/voip_cdr.pm | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index fe05b684a..7c5272edc 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -119,6 +119,12 @@ tie my %temporalities, 'Tie::IxHash', 'skip_dstchannel_prefix' => { 'name' => 'Do not charge for CDRs where the dstchannel starts with:', }, + 'skip_dst_length_less' => { 'name' => 'Do not charge for CDRs where the destination is less than this many digits:', + }, + + 'skip_lastapp' => { 'name' => 'Do not charge for CDRs where the lastapp matches this value', + }, + 'use_duration' => { 'name' => 'Calculate usage based on the duration field instead of the billsec field', 'type' => 'checkbox', }, @@ -555,7 +561,9 @@ sub check_chargable { use_carrierid use_cdrtypenum skip_dcontext - skip_dstchannel_prefix; + skip_dstchannel_prefix + skip_dst_length_less + skip_lastapp ); foreach my $opt (grep !exists($flags{option_cache}->{$_}), @opt ) { $flags{option_cache}->{$opt} = $self->option($opt); @@ -584,10 +592,17 @@ sub check_chargable { if $opt{'skip_dcontext'} =~ /\S/ && grep { $cdr->dcontext eq $_ } split(/\s*,\s*/, $opt{'skip_dcontext'}); - my $len = length($opt{'skip_dstchannel_prefix'}); + my $len_prefix = length($opt{'skip_dstchannel_prefix'}); return "dstchannel starts with $opt{'skip_dstchannel_prefix'}" - if $len - && substr($cdr->dstchannel, 0, $len) eq $opt{'skip_dstchannel_prefix'}; + if $len_prefix + && substr($cdr->dstchannel,0,$len_prefix) eq $opt{'skip_dstchannel_prefix'}; + + my $dst_length = $opt{'skip_dst_length_less'}; + return "destination less than $dst_length digits" + if $dst_length && length($cdr->dst) < $dst_length; + + return "lastapp is $opt{'skip_lastapp'}" + if length($opt{'skip_lastapp'}) && $cdr->lastapp eq $opt{'skip_lastapp'}; #all right then, rate it ''; -- cgit v1.2.1 From af49b2c54c13b14189e23765a9a7102bcf59cb06 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 1 Apr 2009 03:51:19 +0000 Subject: add options to skip CDRs under a defined length and with specific lastapp --- FS/FS/part_pkg/voip_cdr.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index 7c5272edc..f14f14402 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -183,6 +183,7 @@ tie my %temporalities, 'Tie::IxHash', use_amaflags use_disposition use_disposition_taqua use_carrierid use_cdrtypenum skip_dcontext skip_dstchannel_prefix + skip_dst_length_less skip_lastapp use_duration 411_rewrite output_format summarize_usage usage_section -- cgit v1.2.1 From 9483773ebd5056d28ca55fa0895492dd255c2542 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 1 Apr 2009 04:27:25 +0000 Subject: show post-granularity duration if available for all export formats --- FS/FS/cdr.pm | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index 2d9200143..35bb71cf6 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -470,6 +470,15 @@ my %export_names = ( }, ); +my $duration_sub = sub { + my($cdr, %opt) = @_; + if ( $opt{minutes} ) { + $opt{minutes}. ( $opt{granularity} ? 'm' : ' call' ); + } else { + sprintf('%.2fm', $cdr->billsec / 60 ); + } +}; + my %export_formats = ( 'convergent' => [ 'carriername', #CARRIER @@ -491,7 +500,7 @@ my %export_formats = ( sub { time2str('%r', shift->calldate_unix ) }, #TIME 'userfield', #USER 'dst', #NUMBER_DIALED - sub { sprintf('%.2fm', shift->billsec / 60 ) }, #DURATION + $duration_sub, #DURATION #sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE sub { my($cdr, %opt) = @_; $opt{money_char}. $opt{charge}; }, #PRICE ], @@ -501,7 +510,7 @@ my %export_formats = ( #'userfield', #USER 'dst', #NUMBER_DIALED 'src', #called from - sub { sprintf('%.2fm', shift->billsec / 60 ) }, #DURATION + $duration_sub, #DURATION #sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE sub { my($cdr, %opt) = @_; $opt{money_char}. $opt{charge}; }, #PRICE ], @@ -522,9 +531,7 @@ my %export_formats = ( sub { my($cdr, %opt) = @_; $opt{dst_regionname}; }, #DURATION - sub { my($cdr, %opt) = @_; - $opt{minutes}. ( $opt{granularity} ? 'm' : ' call' ); - }, + $duration_sub, #PRICE sub { my($cdr, %opt) = @_; $opt{money_char}. $opt{charge}; }, -- cgit v1.2.1 From d983a08166ca2bfcc16062a4e6820f8985569394 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 2 Apr 2009 00:14:30 +0000 Subject: add some (undocumented/unaccessable to web UI yet) options to package browse to track down packages missing recurring fees --- httemplate/browse/part_pkg.cgi | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi index 801c09f8f..26028b6ad 100755 --- a/httemplate/browse/part_pkg.cgi +++ b/httemplate/browse/part_pkg.cgi @@ -10,7 +10,7 @@ 'agent_pos' => 5, 'query' => { 'select' => $select, 'table' => 'part_pkg', - 'hashref' => {}, + 'hashref' => \%hash, 'extra_sql' => $extra_sql, 'order_by' => "ORDER BY $orderby" }, @@ -41,14 +41,37 @@ my $money_char = $conf->config('money_char') || '$'; my $select = '*'; my $orderby = 'pkgpart'; +my %hash = (); +my $extra_count = ''; + if ( $cgi->param('active') ) { $orderby = 'num_active DESC'; } my $extra_sql = ''; +#if ( $cgi->param('activeONLY') ) { +# $extra_sql = ' WHERE num_active > 0 '; #XXX doesn't affect count... +#} + +if ( $cgi->param('recurring') ) { + $hash{'freq'} = { op=>'!=', value=>'0' }; + $extra_count = ' freq != 0 '; +} + +if ( $cgi->param('missing_recur_fee') ) { + my $missing = "0 = ( SELECT COUNT(*) FROM part_pkg_option + WHERE optionname = 'recur_fee' + AND part_pkg_option.pkgpart = part_pkg.pkgpart + AND CAST ( optionvalue AS NUMERIC ) > 0 + )"; + $extra_sql .= ( ( scalar(keys %hash) || $extra_sql ) ? ' AND ' : ' WHERE ' ). + $missing; +} + unless ( $acl_edit_global ) { - $extra_sql .= ' WHERE '. FS::part_pkg->curuser_pkgs_sql; + $extra_sql .= ( ( scalar(keys %hash) || $extra_sql ) ? ' AND ' : ' WHERE ' ). + FS::part_pkg->curuser_pkgs_sql; } my $agentnums = join(',', $curuser->agentnums); @@ -188,9 +211,7 @@ if ( $acl_edit_global ) { my $typelink = $p. 'edit/agent_type.cgi?'; push @fields, sub { my $part_pkg = shift; [ - map { warn $_; - my $agent_type = $_->agent_type; - warn $agent_type; + map { my $agent_type = $_->agent_type; [ { 'data' => $agent_type->atype, #escape? 'align' => 'left', @@ -362,6 +383,10 @@ $align .= 'lrl'; #rr'; # -------- -my $count_query = "SELECT COUNT(*) FROM part_pkg $extra_sql"; +my $count_extra_sql = $extra_sql; +$count_extra_sql =~ s/^\s*AND /WHERE /i; +$extra_count = ( $count_extra_sql ? ' AND ' : ' WHERE ' ). $extra_count + if $extra_count; +my $count_query = "SELECT COUNT(*) FROM part_pkg $count_extra_sql $extra_count"; -- cgit v1.2.1 From f319a3e27955cc3351f04c12a663f978a6e3d2a3 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 2 Apr 2009 02:36:41 +0000 Subject: more than you ever wanted to know about rounding. http://en.wikipedia.org/wiki/Rounding RT#4666 --- FS/FS/part_pkg/voip_cdr.pm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index f14f14402..c745283d1 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -457,9 +457,11 @@ sub calc_recur { $included_min{$regionnum} -= $minutes; if ( $included_min{$regionnum} < 0 ) { - my $charge_min = 0 - $included_min{$regionnum}; + my $charge_min = 0 - $included_min{$regionnum}; #XXX should preserve + #(display?) this $included_min{$regionnum} = 0; - $charge = sprintf('%.2f', $rate_detail->min_charge * $charge_min ); + $charge = sprintf('%.2f', ( $rate_detail->min_charge * $charge_min ) + + 0.00000001 ); #so 1.005 rounds to 1.01 $charges += $charge; } -- cgit v1.2.1 From 97e26f757913f1c7e7c717690a693e7beeb2b530 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 2 Apr 2009 05:27:24 +0000 Subject: noise reduction --- FS/FS/part_pkg_taxrate.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FS/FS/part_pkg_taxrate.pm b/FS/FS/part_pkg_taxrate.pm index 197bf0fc4..aaf7f60a2 100644 --- a/FS/FS/part_pkg_taxrate.pm +++ b/FS/FS/part_pkg_taxrate.pm @@ -248,8 +248,8 @@ sub batch_import { $part_pkg_taxproduct{'description'} = join(' : ', (map{ $hash->{$_} } qw(groupdesc itemdesc)), - $providers{$hash->{'provider'}}, - $customers{$hash->{'customer'}}, + $providers{$hash->{'provider'}} || '', + $customers{$hash->{'customer'}} || '', ); $part_pkg_taxproduct = new FS::part_pkg_taxproduct \%part_pkg_taxproduct; my $error = $part_pkg_taxproduct->insert; -- cgit v1.2.1 From 00bb047761ea320fb7f1a2b8e45820d6c539b3e0 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 2 Apr 2009 14:56:30 +0000 Subject: obey tax-ship_address in 'manual' geocoding --- httemplate/edit/cust_main.cgi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index d3004f1c6..098de848e 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -363,12 +363,12 @@ function update_address(arg) { if ( <% $taxpre %>error ) { - if ( document.bottomform.elements['country'].value == 'CA' || - document.bottomform.elements['country'].value == 'US' + if ( document.bottomform.elements['<% $taxpre %>country'].value == 'CA' || + document.bottomform.elements['<% $taxpre %>country'].value == 'US' ) { - var url = "cust_main/choose_tax_location.html?data_vendor=cch-zip;city="+document.bottomform.elements['city'].value+";state="+document.bottomform.elements['state'].value+";zip="+document.bottomform.elements['zip'].value+";country="+document.bottomform.elements['country'].value+";"; + var url = "cust_main/choose_tax_location.html?data_vendor=cch-zip;city="+document.bottomform.elements['<% $taxpre %>city'].value+";state="+document.bottomform.elements['<% $taxpre %>state'].value+";zip="+document.bottomform.elements['<% $taxpre %>zip'].value+";country="+document.bottomform.elements['<% $taxpre %>country'].value+";"; // popup a chooser OLgetAJAX( url, update_geocode, 300 ); @@ -483,9 +483,9 @@ function update_geocode() { //alert(what.options[what.selectedIndex].value); var argsHash = eval('(' + what.options[what.selectedIndex].value + ')'); - document.bottomform.elements['city'].value = argsHash['city']; - document.bottomform.elements['state'].value = argsHash['state']; - document.bottomform.elements['zip'].value = argsHash['zip']; + document.bottomform.elements['<% $taxpre %>city'].value = argsHash['city']; + document.bottomform.elements['<% $taxpre %>state'].value = argsHash['state']; + document.bottomform.elements['<% $taxpre %>zip'].value = argsHash['zip']; document.bottomform.elements['geocode'].value = argsHash['geocode']; } -- cgit v1.2.1 From c8ed7ae4cf496300bba2a9a69e2224c5819d2572 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 2 Apr 2009 15:46:49 +0000 Subject: prorating for the fixed recurring portion of voip --- FS/FS/part_pkg/voip_cdr.pm | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index c745283d1..e08050950 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -12,7 +12,7 @@ use FS::rate; use FS::rate_prefix; use FS::rate_detail; -@ISA = qw(FS::part_pkg::flat); +@ISA = qw(FS::part_pkg::prorate); $DEBUG = 0; @@ -55,6 +55,11 @@ tie my %temporalities, 'Tie::IxHash', 'type' => 'checkbox', }, + 'cutoff_day' => { 'name' => 'Billing Day (1 - 28) for prorating. Leave'. + ' blank to charge full first month instead.', + 'default' => '', + }, + 'rating_method' => { 'name' => 'Region rating method', 'type' => 'radio', 'options' => \%rating_method, @@ -175,7 +180,7 @@ tie my %temporalities, 'Tie::IxHash', }, 'fieldorder' => [qw( setup_fee recur_fee recur_temporality unused_credit - rating_method ratenum ignore_unrateable + cutoff_day rating_method ratenum ignore_unrateable default_prefix disable_src domestic_prefix international_prefix @@ -200,7 +205,8 @@ sub calc_setup { #false laziness w/voip_sqlradacct calc_recur resolve it if that one ever gets used again sub calc_recur { - my($self, $cust_pkg, $sdate, $details, $param ) = @_; + my $self = shift; + my($cust_pkg, $sdate, $details, $param ) = @_; #my $last_bill = $cust_pkg->last_bill; my $last_bill = $cust_pkg->get('last_bill'); #->last_bill falls back to setup @@ -544,8 +550,13 @@ sub calc_recur { } #if ( $spool_cdr && length($downstream_cdr) ) - $charges += $self->option('recur_fee') - if $param->{'increment_next_bill'}; + if ($param->{'increment_next_bill'}) { + if ( $self->option('cutoff_day', 1) ) { + $charges += $self->SUPER::calc_recur(@_); + } else { + $charges += $self->option('recur_fee') + } + } $charges; } -- cgit v1.2.1 From 6d63ac7337203c5ea73aebce87d93d663606f386 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 2 Apr 2009 17:47:33 +0000 Subject: separate checkbox for enabling prorate feature --- FS/FS/part_pkg/voip_cdr.pm | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index e08050950..34b5571e6 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -55,9 +55,12 @@ tie my %temporalities, 'Tie::IxHash', 'type' => 'checkbox', }, - 'cutoff_day' => { 'name' => 'Billing Day (1 - 28) for prorating. Leave'. - ' blank to charge full first month instead.', - 'default' => '', + 'enable_prorate' => { 'name' => 'Enable prorating of the first month', + 'type' => 'checkbox', + }, + + 'cutoff_day' => { 'name' => 'Billing Day (1 - 28) for prorating ', + 'default' => '1', }, 'rating_method' => { 'name' => 'Region rating method', @@ -180,7 +183,8 @@ tie my %temporalities, 'Tie::IxHash', }, 'fieldorder' => [qw( setup_fee recur_fee recur_temporality unused_credit - cutoff_day rating_method ratenum ignore_unrateable + enable_prorate cutoff_day + rating_method ratenum ignore_unrateable default_prefix disable_src domestic_prefix international_prefix @@ -551,7 +555,7 @@ sub calc_recur { } #if ( $spool_cdr && length($downstream_cdr) ) if ($param->{'increment_next_bill'}) { - if ( $self->option('cutoff_day', 1) ) { + if ( $self->option('enable_prorate', 1) ) { $charges += $self->SUPER::calc_recur(@_); } else { $charges += $self->option('recur_fee') -- cgit v1.2.1 From 8e9fad68fed8b7821fd7736b7947fb45983ff9c0 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 2 Apr 2009 20:22:32 +0000 Subject: Net 20 as well --- httemplate/edit/cust_main/billing.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index 8724db9dc..e175e21cc 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -429,7 +429,7 @@ % if ( $custnum ) { @@ -19,101 +23,16 @@

% } -<% &ntable("#cccccc") %> - -%# agent -<% include('/elements/tr-select-agent.html', - 'curr_value' => $cust_main->agentnum, - 'label' => "${r}Agent", - 'empty_label' => 'Select agent', - 'disable_empty' => ( $cust_main->agentnum ? 1 : 0 ), - ) -%> - -%# agent_custid -% if ( $conf->exists('cust_main-edit_agent_custid') ) { - - - Customer identifier - - - -% } else { - - - -% } - -%# referral (advertising source) -%my $refnum = $cust_main->refnum || $conf->config('referraldefault') || 0; -%if ( $custnum && ! $conf->exists('editreferrals') ) { - - - -% } else { - - <% include('/elements/tr-select-part_referral.html', - 'curr_value' => $refnum - ) - %> -% } - - -%# referring customer -%my $referring_cust_main = ''; -%if ( $cust_main->referral_custnum -% and $referring_cust_main = -% qsearchs('cust_main', { custnum => $cust_main->referral_custnum } ) -%) { - - - Referring customer - - <% $cust_main->referral_custnum %>: <% $referring_cust_main->name %> - - - -% } elsif ( ! $conf->exists('disable_customer_referrals') ) { - - - - Referring customer - - - <% include('/elements/search-cust_main.html', - 'field_name' => 'referral_custnum', - ) - %> - - -% } else { - - - -% } - - - - - +%# agent, agent_custid, refnum (advertising source), referral_custnum +<% include('cust_main/top_misc.html', $cust_main, 'custnum' => $custnum ) %> +%# birthdate % if ( $conf->exists('cust_main-enable_birthdate') ) { -
- <% ntable("#cccccc", 2) %> - <% include ('/elements/tr-input-date-field.html', - 'birthdate', - $cust_main->birthdate, - 'Date of Birth', - $conf->config('date_format') || "%m/%d/%Y", - 1) - %> - - - + <% include('cust_main/birthdate.html', $cust_main) %> % } - +%# contact info % my $same_checked = ''; % my $ship_disabled = ''; @@ -129,7 +48,8 @@ % }

-Billing address +Billing address + <% include('cust_main/contact.html', 'cust_main' => $cust_main, 'pre' => '', @@ -199,7 +119,8 @@ function samechanged(what) {
-Service address +Service address + (>same as billing address) <% include('cust_main/contact.html', 'cust_main' => $cust_main, @@ -209,473 +130,69 @@ Service address ) %> - - - +%# billing info <% include( 'cust_main/billing.html', $cust_main, 'payinfo' => $payinfo, 'invoicing_list' => \@invoicing_list, ) %> -<% include( '/elements/xmlhttp.html', - 'url' => $p.'misc/xmlhttp-cust_main-address_standardize.html', - 'subs' => [ 'address_standardize' ], - #'method' => 'POST', #could get too long? - ) -%> - - + -
% foreach my $hidden ( -% 'birthdate', -% -% 'custnum', 'agentnum', 'agent_custid', 'refnum', 'referral_custnum', -% 'last', 'first', 'ss', 'company', -% 'address1', 'address2', 'city', -% 'county', 'state', 'zip', 'country', -% 'daytime', 'night', 'fax', -% 'stateid', 'stateid_state', -% -% 'same', -% -% 'ship_last', 'ship_first', 'ship_company', -% 'ship_address1', 'ship_address2', 'ship_city', -% 'ship_county', 'ship_state', 'ship_zip', 'ship_country', -% 'ship_daytime','ship_night', 'ship_fax', -% -% 'geocode', -% -% 'select', #XXX key -% -% 'payauto', -% 'payinfo', 'payinfo1', 'payinfo2', 'paytype', -% 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', -% 'paystart_month', 'paystart_year', 'payissue', -% 'payip', -% 'paid', -% -% 'tax', -% 'invoicing_list', 'invoicing_list_POST', 'invoicing_list_FAX', -% 'invoice_terms', -% 'spool_cdr', -% 'squelch_cdr' -% ) { -% - - -% } -% -% my $ro_comments = $conf->exists('cust_main-use_comments')?'':'readonly'; -% if (!$ro_comments || $cust_main->comments) { - -
Comments -<% &ntable("#cccccc") %> - - - - - - -% -% } -% -%unless ( $custnum ) { -% # pry the wrong place for this logic. also pretty expensive -% #use FS::part_pkg; -% -% #false laziness, copied from FS::cust_pkg::order -% my $pkgpart; -% my $agentnum = ''; -% my @agents = $FS::CurrentUser::CurrentUser->agents; -% if ( scalar(@agents) == 1 ) { -% # $pkgpart->{PKGPART} is true iff $custnum may purchase PKGPART -% $pkgpart = $agents[0]->pkgpart_hashref; -% $agentnum = $agents[0]->agentnum; -% } else { -% #can't know (agent not chosen), so, allow all -% $agentnum = 'all'; -% my %typenum; -% foreach my $agent ( @agents ) { -% next if $typenum{$agent->typenum}++; -% $pkgpart->{$_}++ foreach keys %{ $agent->pkgpart_hashref } -% } -% } -% #eslaf -% -% my @part_pkg = grep { $_->svcpart('svc_acct') -% && ( $pkgpart->{ $_->pkgpart } -% || $agentnum eq 'all' -% || ( $agentnum ne 'all' -% && $agentnum -% && $_->agentnum -% && $_->agentnum == $agentnum -% ) -% ) -% } -% qsearch( 'part_pkg', { 'disabled' => '' }, '', 'ORDER BY pkg' ); # case? -% -% if ( @part_pkg ) { -% -% # print "

First package", &itable("#cccccc", "0 ALIGN=LEFT"), -% #apiabuse & undesirable wrapping -% -% - -
First package - <% ntable("#cccccc") %> - - - - <% include('cust_main/select-domain.html', - 'pkgparts' => \@part_pkg, - 'saved_pkgpart' => $saved_pkgpart, - 'saved_domsvc' => $saved_domsvc, - ) - %> - - -% -% #false laziness: (mostly) copied from edit/svc_acct.cgi -% #$ulen = $svc_acct->dbdef_table->column('username')->length; -% my $ulen = dbdef->table('svc_acct')->column('username')->length; -% my $ulen2 = $ulen+2; -% my $passwordmax = $conf->config('passwordmax') || 8; -% my $pmax2 = $passwordmax + 2; -% - - - - Username - - MAXLENGTH=<% $ulen %>> - - - - - Domain - - - - - - - Password - - MAXLENGTH=<% $passwordmax %>> - (blank to generate) - - - - - Access number - <% FS::svc_acct_pop::popselector($popnum) %> - - -% } +% 'payauto', +% 'payinfo', 'payinfo1', 'payinfo2', 'paytype', +% 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', +% 'paystart_month', 'paystart_year', 'payissue', +% 'payip', +% 'paid', +% ) { + % } +<% include('cust_main/bottomfixup.html') %> - -
-" onClick="document.bottomform.submitButton.disabled=true; bottomfixup(this.form);">
+" + onClick = "this.disabled=true; bottomfixup(this.form);" +>
<% include('/elements/footer.html') %> @@ -685,52 +202,49 @@ function copyelement(from, to) { die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Edit customer'); -#for misplaced logic below -#use FS::part_pkg; - -#for false laziness below (now more properly lazy) -#use FS::svc_acct_pop; - -#for (other) false laziness below -#use FS::agent; -#use FS::type_pkgs; - my $conf = new FS::Conf; -my $taxpre = $conf->exists('tax-ship_address') ? 'ship_' : ''; #get record -my($custnum, $username, $password, $popnum, $cust_main, $saved_pkgpart, $saved_domsvc); -my(@invoicing_list); -my ($ss,$stateid,$payinfo); +my($custnum, $cust_main, $ss, $stateid, $payinfo, @invoicing_list); my $same = ''; +my $pkgpart_svcpart = ''; #first_pkg +my($username, $password, $popnum, $saved_domsvc) = ( '', '', 0, 0 ); #svc_acct +my %svc_phone = (); + if ( $cgi->param('error') ) { + $cust_main = new FS::cust_main ( { map { $_, scalar($cgi->param($_)) } fields('cust_main') } ); + $custnum = $cust_main->custnum; - $saved_domsvc = $cgi->param('domsvc') || ''; - if ( $saved_domsvc =~ /^(\d+)$/ ) { - $saved_domsvc = $1; - } else { - $saved_domsvc = ''; - } - $saved_pkgpart = $cgi->param('pkgpart_svcpart') || ''; - if ( $saved_pkgpart =~ /^(\d+)_/ ) { - $saved_pkgpart = $1; - } else { - $saved_pkgpart = ''; - } - $username = $cgi->param('username'); - $password = $cgi->param('_password'); - $popnum = $cgi->param('popnum'); @invoicing_list = split( /\s*,\s*/, $cgi->param('invoicing_list') ); $same = $cgi->param('same'); $cust_main->setfield('paid' => $cgi->param('paid')) if $cgi->param('paid'); $ss = $cust_main->ss; # don't mask an entered value on errors $stateid = $cust_main->stateid; # don't mask an entered value on errors $payinfo = $cust_main->payinfo; # don't mask an entered value on errors + + $pkgpart_svcpart = $cgi->param('pkgpart_svcpart') || ''; + + #svc_acct + $username = $cgi->param('username'); + $password = $cgi->param('_password'); + $popnum = $cgi->param('popnum'); + $saved_domsvc = $cgi->param('domsvc') || ''; + if ( $saved_domsvc =~ /^(\d+)$/ ) { + $saved_domsvc = $1; + } else { + $saved_domsvc = ''; + } + + #svc_phone + $svc_phone{$_} = $cgi->param($_) + foreach qw( countrycode phonenum sip_password pin phone_name ); + } elsif ( $cgi->keywords ) { #editing + my( $query ) = $cgi->keywords; $query =~ /^(\d+)$/; $custnum=$1; @@ -741,31 +255,24 @@ if ( $cgi->param('error') ) { $paycvv =~ s/./*/g; $cust_main->paycvv($paycvv); } - $saved_pkgpart = 0; - $saved_domsvc = 0; - $username = ''; - $password = ''; - $popnum = 0; @invoicing_list = $cust_main->invoicing_list; $ss = $cust_main->masked('ss'); $stateid = $cust_main->masked('stateid'); $payinfo = $cust_main->paymask; -} else { + +} else { #new customer + $custnum=''; $cust_main = new FS::cust_main ( {} ); $cust_main->otaker( &getotaker ); $cust_main->referral_custnum( $cgi->param('referral_custnum') ); - $saved_pkgpart = 0; - $saved_domsvc = 0; - $username = ''; - $password = ''; - $popnum = 0; @invoicing_list = (); push @invoicing_list, 'POST' unless $conf->exists('disablepostalinvoicedefault'); $ss = ''; $stateid = ''; $payinfo = ''; + } my $error = $cgi->param('error'); diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index e175e21cc..353f2b9a0 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -1,18 +1,15 @@ %if ( $payby_default eq 'HIDE' ) { % % $cust_main->payby('BILL') unless $cust_main->payby; +% my $payby = $cust_main->payby; - - - - -
+ - + % foreach my $field (qw( payname paycvv paystart_month paystart_year payissue payip paytype paystate )) { - + % } @@ -27,24 +24,18 @@ % die "unrecognized expiration date format: $date"; % } - - - -
- -
+ + -
- % } else { % % my $r = qq!* !; -
Billing information +
Billing information <% &ntable("#cccccc") %> @@ -128,13 +119,13 @@ % ''. % % qq!!. -% qq!!. +% qq!!. % % qq!!. % '!. -% '!. % '!. +% '!. % % qq!!. -% qq!!. +% qq!!. % -% qq!'. +% qq!'. % % '
${r}Card number
${r}Expiration '. % % include('/elements/select-month_year.html', -% 'prefix' => 'exp', +% 'prefix' => 'CARD_exp', % 'selected_date' => % ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->paydate : '' ), % ). @@ -145,14 +136,14 @@ % % qq!(help)!. % qq!'. +% ''. % % % qq!
Start date '. % % include('/elements/select-month_year.html', -% 'prefix' => 'paystart', +% 'prefix' => 'CARD_paystart', % 'disabled' => $disabled, % 'empty_option' => 1, % 'start_year' => 2000, @@ -167,12 +158,12 @@ % ). % % qq! or Issue number !. -% '
${r}Exact name on card
Charge future payments to this card automatically
Charge future payments to this card automatically
', % @@ -181,21 +172,21 @@ % ''. % % qq!!. -% qq!'. -% qq!'. +% qq!!. % % qq!!. -% qq!!. % -% qq!!. -% qq!!. +% qq!!. +% qq!!. % % qq!!. -% qq!!. +% qq!!. % ( $conf->exists('show_bankstate') ? % qq!!. % qq!" -% : '' % ). % % -% qq!'. +% qq!'. % % ''. % ''. @@ -223,11 +214,11 @@ % '
${r}Account number TypeType
${r}ABA/Routing number !. +% qq! !. % qq!(help)!. % qq!
${r}Bank name
$paystate_label!. @@ -203,14 +194,14 @@ % 'empty' => '(choose)', % 'state' => $cust_main->paystate, % 'country' => $cust_main->country, -% 'prefix' => 'pay', +% 'prefix' => 'CHEK_pay', % ). "
Charge future payments to this electronic check automatically
Charge future payments to this electronic check automatically
 
 
'. % % qq!!. -% qq!!. +% qq!!. % -% qq!!. -% qq!!. -% qq!!. +% qq!!. +% qq!!. +% qq!!. % % ''. % ''. @@ -243,13 +234,13 @@ % '
${r}Phone number
 
 
'. % % qq!!. -% qq!!. +% qq!!. % -% qq!!. -% qq!!. +% qq!!. +% qq!!. % % qq!!. -% qq!!. +% qq!!. % % ''. % ''. @@ -264,13 +255,13 @@ % '
P.O.
Attention
 
 
'. % % qq!!. -% qq!!. +% qq!!. % % qq!!. % '
${r}Approved by
${r}Expiration '. % % include('/elements/select-month_year.html', -% 'prefix' => 'exp', +% 'prefix' => 'COMP_exp', % 'selected_date' => % ( $payby eq 'COMP' ? $cust_main->paydate : '' ), % ). @@ -290,7 +281,7 @@ % ''. % % qq!!. -% qq!!. +% qq!!. % % ''. % ''. @@ -306,7 +297,7 @@ % '
${r}Amount
 
 
'. % % qq!!. -% qq!!. +% qq!!. % % ''. % ''. @@ -322,7 +313,7 @@ % '
${r}Amount
 
 
'. % % qq!!. -% qq!!. +% qq!!. % % ''. % ''. @@ -336,48 +327,33 @@ % ); % % #this should use FS::payby -% my %allopt = ( -% 'CARD' => 'Credit card', -% 'CHEK' => 'Electronic check', -% 'LECB' => 'Phone bill billing', -% 'BILL' => 'Billing', -% 'CASH' => 'Cash', # initial payment, then billing', -% 'WEST' => 'Western Union', # initial payment, then billing', -% 'MCRD' => 'Manual credit card', # initial payment, then billing', -% 'COMP' => 'Complimentary', -% ); -% if ( $cust_main->custnum ) { #don't offer CASH/WEST/MCRD initial payment types -% # when editing customer +% my @allopt = qw( CARD CHEK LECB BILL CASH WEST MCRD COMP ); +% +% my %allopt = map { $_ => FS::payby->shortname($_) } @allopt; +% +% if ( $cust_main->custnum ) { +% #don't offer CASH/WEST/MCRD initial payment types when editing customer % delete $allopt{$_} for qw(CASH WEST MCRD); % } % -% tie my %options, 'Tie::IxHash', -% map { $_ => $allopt{$_} } -% grep { exists $allopt{$_} } -% @payby; +% my @options = grep exists( $allopt{$_} ), @payby; % % my %payby2option = ( -% ( map { $_ => $_ } keys %options ), +% ( map { $_ => $_ } @options ), % 'DCRD' => 'CARD', % 'DCHK' => 'CHEK', % ); -% -% my $widget = new HTML::Widgets::SelectLayers( -% 'options' => \%options, -% #'form_name' => 'dummy', -% #'form_action' => 'nothingyet', -% #chops bottom of page in IE# 'under_position' => 'absolute', -% 'html_between' => '
${r}Amount
 
 
', -% 'selected_layer' => $payby2option{$payby || $payby_default || $payby[0] }, -% 'layer_callback' => sub { my $layer = shift; $payby{$layer}; }, -% ); -% -% - -
<% $widget->html %> - -
+
+ <% include( '/elements/selectlayers.html', + 'field' => 'payby', + 'curr_value' => $payby2option{$payby || $payby_default || $payby[0] }, + 'options' => \@options, + 'labels' => \%allopt, + 'html_between' => '
', + 'layer_callback' => sub { my $layer = shift; $payby{$layer}; }, + ) + %> <% &ntable("#cccccc") %> @@ -457,8 +433,6 @@ - - <% $r %> required fields % } diff --git a/httemplate/edit/cust_main/birthdate.html b/httemplate/edit/cust_main/birthdate.html new file mode 100644 index 000000000..415aba3c4 --- /dev/null +++ b/httemplate/edit/cust_main/birthdate.html @@ -0,0 +1,15 @@ +<% ntable("#cccccc", 2) %> + <% include ('/elements/tr-input-date-field.html', + 'birthdate', + $cust_main->birthdate, + 'Date of Birth', + $conf->config('date_format') || "%m/%d/%Y", + 1) + %> + +<%init> + +my( $cust_main, %opt ) = @_; +my $conf = new FS::Conf; + + diff --git a/httemplate/edit/cust_main/bottomfixup.html b/httemplate/edit/cust_main/bottomfixup.html new file mode 100644 index 000000000..3eb43e0e5 --- /dev/null +++ b/httemplate/edit/cust_main/bottomfixup.html @@ -0,0 +1,12 @@ +<% include('/elements/init_overlib.html') %> + +<% include( '/elements/xmlhttp.html', + 'url' => $p.'misc/xmlhttp-cust_main-address_standardize.html', + 'subs' => [ 'address_standardize' ], + #'method' => 'POST', #could get too long? + ) +%> + + diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js new file mode 100644 index 000000000..efe2215c8 --- /dev/null +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -0,0 +1,278 @@ +function bottomfixup(what) { + + var layervars = new Array( + 'payauto', + 'payinfo', 'payinfo1', 'payinfo2', 'paytype', + 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', + 'paystart_month', 'paystart_year', 'payissue', + 'payip', + 'paid' + ); + + var cf = document.CustomerForm; + var payby = cf.payby.options[cf.payby.selectedIndex].value; + for ( f=0; f < layervars.length; f++ ) { + var field = layervars[f]; + copyelement( cf.elements[payby + '_' + field], + cf.elements[field] + ); + } + + //this part does USPS address correction + + // XXX should this be first and should we update the form fields that are + // displayed??? + + var cf = document.CustomerForm; + + var state_el = cf.elements['state']; + var ship_state_el = cf.elements['ship_state']; + + //address_standardize( + var cust_main = new Array( + 'company', cf.elements['company'].value, + 'address1', cf.elements['address1'].value, + 'address2', cf.elements['address2'].value, + 'city', cf.elements['city'].value, + 'state', state_el.options[ state_el.selectedIndex ].value, + 'zip', cf.elements['zip'].value, + + 'ship_company', cf.elements['ship_company'].value, + 'ship_address1', cf.elements['ship_address1'].value, + 'ship_address2', cf.elements['ship_address2'].value, + 'ship_city', cf.elements['ship_city'].value, + 'ship_state', ship_state_el.options[ ship_state_el.selectedIndex ].value, + 'ship_zip', cf.elements['ship_zip'].value + ); + + address_standardize( cust_main, update_address ); + +} + +var standardize_address; + +function update_address(arg) { + + var argsHash = eval('(' + arg + ')'); + + var changed = argsHash['address_standardized']; + var ship_changed = argsHash['ship_address_standardized']; + var error = argsHash['error']; + var ship_error = argsHash['ship_error']; + + //yay closures + standardize_address = function () { + + var cf = document.CustomerForm; + var state_el = cf.elements['state']; + var ship_state_el = cf.elements['ship_state']; + + if ( changed ) { + cf.elements['company'].value = argsHash['new_company']; + cf.elements['address1'].value = argsHash['new_address1']; + cf.elements['address2'].value = argsHash['new_address2']; + cf.elements['city'].value = argsHash['new_city']; + setselect(cf.elements['state'], argsHash['new_state']); + cf.elements['zip'].value = argsHash['new_zip']; + } + + if ( ship_changed ) { + cf.elements['ship_company'].value = argsHash['new_ship_company']; + cf.elements['ship_address1'].value = argsHash['new_ship_address1']; + cf.elements['ship_address2'].value = argsHash['new_ship_address2']; + cf.elements['ship_city'].value = argsHash['new_ship_city']; + setselect(cf.elements['ship_state'], argsHash['new_ship_state']); + cf.elements['ship_zip'].value = argsHash['new_ship_zip']; + } + + } + + var cf = document.CustomerForm; + +% if ( $conf->exists('enable_taxproducts') ) { + + if ( <% $taxpre %>error ) { + + var country_el = cf.elements['<% $taxpre %>country']; + var country = country_el.options[ country_el.selectedIndex ].value; + + if ( country == 'CA' || country == 'US' ) { + + var state_el = cf.elements['<% $taxpre %>state']; + var state = state_el.options[ state_el.selectedIndex ].value; + + var url = "cust_main/choose_tax_location.html" + + "?data_vendor=cch-zip" + + ";city=" + cf.elements['<% $taxpre %>city'].value + + ";state=" + state + + ";zip=" + cf.elements['<% $taxpre %>zip'].value + + ";country=" + country + + ";"; + + // popup a chooser + OLgetAJAX( url, update_geocode, 300 ); + + } else { + + cf.elements['geocode'].value = 'DEFAULT'; + cf.submit(); + + } + + } else + +% } + + if ( changed || ship_changed ) { + +% if ( $conf->exists('cust_main-auto_standardize_address') ) { + + standardize_address(); + cf.submit(); + +% } else { + + // popup a confirmation popup + + var confirm_change = + '

Confirm address standardization

' + + ''; + + if ( changed ) { + + confirm_change = confirm_change + + '' + + ''; + // + ''; + + if ( argsHash['company'] || argsHash['new_company'] ) { + confirm_change = confirm_change + + ''; + } + + confirm_change = confirm_change + + '' + + '' + + '' + + ''; + + } + + if ( ship_changed ) { + + confirm_change = confirm_change + + '' + + ''; + // + ''; + + if ( argsHash['ship_company'] || argsHash['new_ship_company'] ) { + confirm_change = confirm_change + + ''; + } + + confirm_change = confirm_change + + '' + + '' + + '' + + ''; + + } + + var addresses = 'address'; + var height = 268; + if ( changed && ship_changed ) { + addresses = 'addresses'; + height = 396; // #what + } + + confirm_change = confirm_change + + '' + + '' + + + '
Entered billing addressStandardized billing address
  
' + argsHash['company'] + + '' + argsHash['new_company'] + '
' + argsHash['address1'] + + '' + argsHash['new_address1'] + '
' + argsHash['address2'] + + '' + argsHash['new_address2'] + '
' + argsHash['city'] + ', ' + argsHash['state'] + ' ' + argsHash['zip'] + + '' + argsHash['new_city'] + ', ' + argsHash['new_state'] + ' ' + argsHash['new_zip'] + '
  
Entered service addressStandardized service address
  
' + argsHash['ship_company'] + + '' + argsHash['new_ship_company'] + '
' + argsHash['ship_address1'] + + '' + argsHash['new_ship_address1'] + '
' + argsHash['ship_address2'] + + '' + argsHash['new_ship_address2'] + '
' + argsHash['ship_city'] + ', ' + argsHash['ship_state'] + ' ' + argsHash['ship_zip'] + + '' + argsHash['new_ship_city'] + ', ' + argsHash['new_ship_state'] + ' ' + argsHash['new_ship_zip'] + '
  
' + + '' + + '' + + '' + + '
' + + '
'; + + overlib( confirm_change, CAPTION, 'Confirm address standardization', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, height, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + +% } + + } else { + + cf.submit(); + + } + +} + +function update_geocode() { + + //yay closures + set_geocode = function (what) { + + var cf = document.CustomerForm; + + //alert(what.options[what.selectedIndex].value); + var argsHash = eval('(' + what.options[what.selectedIndex].value + ')'); + cf.elements['<% $taxpre %>city'].value = argsHash['city']; + setselect(cf.elements['<% $taxpre %>state'], argsHash['state']); + cf.elements['<% $taxpre %>zip'].value = argsHash['zip']; + cf.elements['geocode'].value = argsHash['geocode']; + + } + + // popup a chooser + + overlib( OLresponseAJAX, CAPTION, 'Select tax location', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + +} + +function copyelement(from, to) { + if ( from == undefined ) { + to.value = ''; + } else if ( from.type == 'select-one' ) { + to.value = from.options[from.selectedIndex].value; + //alert(from + " (" + from.type + "): " + to.name + " => (" + from.selectedIndex + ") " + to.value); + } else if ( from.type == 'checkbox' ) { + if ( from.checked ) { + to.value = from.value; + } else { + to.value = ''; + } + } else { + if ( from.value == undefined ) { + to.value = ''; + } else { + to.value = from.value; + } + } + //alert(from + " (" + from.type + "): " + to.name + " => " + to.value); +} + +function setselect(el, value) { + + for ( var s = 0; s < el.options.length; s++ ) { + if ( el.options[s].value == value ) { + el.selectedIndex = s; + } + } + +} +<%init> + +my $conf = new FS::Conf; + +my $taxpre = $conf->exists('tax-ship_address') ? 'ship_' : ''; + + diff --git a/httemplate/edit/cust_main/choose_tax_location.html b/httemplate/edit/cust_main/choose_tax_location.html index bd8b95cb6..2a4192632 100644 --- a/httemplate/edit/cust_main/choose_tax_location.html +++ b/httemplate/edit/cust_main/choose_tax_location.html @@ -26,8 +26,8 @@

- - + +
diff --git a/httemplate/edit/cust_main/first_pkg.html b/httemplate/edit/cust_main/first_pkg.html new file mode 100644 index 000000000..0de33c025 --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg.html @@ -0,0 +1,55 @@ +% if ( @part_pkg ) { + +

+ First package + <% ntable("#cccccc") %> + + + + <% include('first_pkg/select-part_pkg.html', + 'part_pkg' => \@part_pkg, + %opt, + # map { $_ => $opt{$_} } qw( pkgpart_svcpart saved_domsvc ) + ) + %> + +% } +<%init> + +my( $cust_main, %opt ) = @_; + +# pry the wrong place for this logic. also pretty expensive + +#false laziness, copied from FS::cust_pkg::order +my $pkgpart; +my $agentnum = ''; +my @agents = $FS::CurrentUser::CurrentUser->agents; +if ( scalar(@agents) == 1 ) { + # $pkgpart->{PKGPART} is true iff $custnum may purchase PKGPART + $pkgpart = $agents[0]->pkgpart_hashref; + $agentnum = $agents[0]->agentnum; +} else { + #can't know (agent not chosen), so, allow all + $agentnum = 'all'; + my %typenum; + foreach my $agent ( @agents ) { + next if $typenum{$agent->typenum}++; + $pkgpart->{$_}++ foreach keys %{ $agent->pkgpart_hashref } + } +} +#eslaf + +my @first_svc = ( 'svc_acct', 'svc_phone' ); + +my @part_pkg = + grep { $_->svcpart(\@first_svc) + && ( $pkgpart->{ $_->pkgpart } + || $agentnum eq 'all' + || ( $agentnum ne 'all' && $agentnum && $_->agentnum + && $_->agentnum == $agentnum + ) + ) + } + qsearch( 'part_pkg', { 'disabled' => '' }, '', 'ORDER BY pkg' ); # case? + + diff --git a/httemplate/edit/cust_main/first_pkg/select-part_pkg.html b/httemplate/edit/cust_main/first_pkg/select-part_pkg.html new file mode 100644 index 000000000..1b62035b2 --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg/select-part_pkg.html @@ -0,0 +1,164 @@ +<% include('/elements/xmlhttp.html', + 'url' => $p.'misc/svc_acct-domains.cgi', + 'subs' => [ $opt{'prefix'}. 'get_domains' ], + ) +%> + +<% include('/elements/xmlhttp.html', + 'url' => $p.'misc/part_svc-columns.cgi', + 'subs' => [ $opt{'prefix'}. 'get_part_svc' ], + ) +%> + + + +<% include( '/elements/selectlayers.html', + 'field' => $opt{'prefix'}. 'pkgpart_svcpart', + 'curr_value' => $opt{pkgpart_svcpart}, + 'options' => \@options, + 'labels' => \%labels, + 'html_between' => '', + #'onchange' => $opt{'prefix'}. 'pkgpart_svcpart_changed(this,0);', + 'onchange' => $opt{'prefix'}. 'pkgpart_svcpart_changed_too(what,0)', + + 'layer_callback' => $layer_callback, + 'layermap' => \%layermap, + ) +%> + + + +<%init> + +my %opt = @_; + +foreach my $opt (qw( svc_part pkgparts saved_pkgpart saved_domsvc prefix)) { + $opt{$_} = '' unless exists($opt{$_}) && defined($opt{$_}); +} +$opt{saved_domsvc} = 0 unless $opt{saved_domsvc}; + +my @part_pkg = @{$opt{'part_pkg'}}; + +my @first_svc = ( 'svc_acct', 'svc_phone' ); + +my %pkgpart_svcpart = (); +my %svcdb = (); +my %layermap = (); +foreach my $part_pkg ( @part_pkg ) { + my $pkgpart = $part_pkg->pkgpart; + my $pkgpart_svcpart = $pkgpart. "_". $part_pkg->svcpart(\@first_svc); + $pkgpart_svcpart{$pkgpart} = $pkgpart_svcpart; + $svcdb{$pkgpart} = $part_pkg->part_svc(\@first_svc)->svcdb; + $layermap{$pkgpart_svcpart} = $svcdb{$pkgpart}; +} + +my @options = ( '', map $pkgpart_svcpart{ $_->pkgpart }, @part_pkg ); +my %labels = ( '' => '(none)', + map { $pkgpart_svcpart{ $_->pkgpart } + => $_->pkg. " - ". $_->comment + } + @part_pkg + ); + +my $layer_callback = sub { + my $layer = shift; + #$layer_fields, $layer_values, $layer_prefix + +# my( $pkgpart, $svcpart ) = split('_', $layer); +# my $svcdb = $svcdb{$pkgpart}; + my $svcdb = $layer; + + return '' unless $svcdb; #'




' + + #full path cause we're being slung around as a coderef (mason closures?) + include("/edit/cust_main/first_pkg/$svcdb.html", %opt, ); +}; + + diff --git a/httemplate/edit/cust_main/first_pkg/svc_acct.html b/httemplate/edit/cust_main/first_pkg/svc_acct.html new file mode 100644 index 000000000..91ee7a56c --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg/svc_acct.html @@ -0,0 +1,58 @@ +<% ntable("#cccccc") %> + + + Username + + + MAXLENGTH = <% $ulen %> + > + + + + + Domain + + + + + + + Password + + + MAXLENGTH = <% $passwordmax %>> + (blank to generate) + + + + + Access number + <% FS::svc_acct_pop::popselector($opt{'popnum'}) %> + + + + +<%init> + +#use FS::svc_acct_pop; + +my( %opt ) = @_; + +my $conf = new FS::Conf; + +#false laziness: (mostly) copied from edit/svc_acct.cgi +#$ulen = $svc_acct->dbdef_table->column('username')->length; +my $ulen = dbdef->table('svc_acct')->column('username')->length; +my $ulen2 = $ulen+2; +my $passwordmax = $conf->config('passwordmax') || 8; +my $pmax2 = $passwordmax + 2; + + diff --git a/httemplate/edit/cust_main/first_pkg/svc_phone.html b/httemplate/edit/cust_main/first_pkg/svc_phone.html new file mode 100644 index 000000000..70e013ece --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg/svc_phone.html @@ -0,0 +1,82 @@ +<% ntable("#cccccc") %> + +%#XXX this should be hidden or something in most/all cases + + Country code + + + + + +%#we don't know the svcpart until the dropdown is changed :/ +%#<% include('/elements/tr-select-did.html', +%# 'label' => 'Phone number', +%# 'curr_value' => $opt{'phonenum'}, +%# ) +%#%> + + Phone Number + + + + + + + SIP password + + + + + + + Voicemail PIN + + + + + +%#XXX this should be hidden or something in most/all cases + + Name + + + + + + + +<%init> + +my( %opt ) = @_; + +#my $conf = new FS::Conf; + + diff --git a/httemplate/edit/cust_main/select-domain.html b/httemplate/edit/cust_main/select-domain.html deleted file mode 100644 index bec1e834c..000000000 --- a/httemplate/edit/cust_main/select-domain.html +++ /dev/null @@ -1,67 +0,0 @@ - -<% include('/elements/xmlhttp.html', - 'url' => $p.'misc/svc_acct-domains.cgi', - 'subs' => [ $opt{'prefix'}. 'get_domains' ], - ) -%> - - - - - - -<%init> -my %opt = @_; -foreach my $opt (qw( svc_part pkgparts saved_pkgpart saved_domsvc prefix)) { - $opt{$_} = '' unless exists($opt{$_}) && defined($opt{$_}); -} -$opt{saved_domsvc} = 0 unless $opt{saved_domsvc}; -my @part_pkg = @{$opt{'pkgparts'}}; - - - diff --git a/httemplate/edit/cust_main/top_misc.html b/httemplate/edit/cust_main/top_misc.html new file mode 100644 index 000000000..5aaa0b0cc --- /dev/null +++ b/httemplate/edit/cust_main/top_misc.html @@ -0,0 +1,87 @@ +<% &ntable("#cccccc") %> + +%# agent +<% include('/elements/tr-select-agent.html', + 'curr_value' => $cust_main->agentnum, + 'label' => "${r}Agent", + 'empty_label' => 'Select agent', + 'disable_empty' => ( $cust_main->agentnum ? 1 : 0 ), + ) +%> + +%# agent_custid +% if ( $conf->exists('cust_main-edit_agent_custid') ) { + + + Customer identifier + + + +% } else { + + + +% } + +%# referral (advertising source) +%my $refnum = $cust_main->refnum || $conf->config('referraldefault') || 0; +%if ( $custnum && ! $conf->exists('editreferrals') ) { + + + +% } else { + + <% include('/elements/tr-select-part_referral.html', + 'curr_value' => $refnum + ) + %> +% } + + +%# referring customer +%my $referring_cust_main = ''; +%if ( $cust_main->referral_custnum +% and $referring_cust_main = +% qsearchs('cust_main', { custnum => $cust_main->referral_custnum } ) +%) { + + + Referring customer + + <% $cust_main->referral_custnum %>: <% $referring_cust_main->name %> + + + +% } elsif ( ! $conf->exists('disable_customer_referrals') ) { + + + + Referring customer + + + <% include('/elements/search-cust_main.html', + 'field_name' => 'referral_custnum', + ) + %> + + +% } else { + + + +% } + + + + +<%init> + +my( $cust_main, %opt ) = @_; + +my $custnum = $opt{'custnum'}; + +my $conf = new FS::Conf; + +my $r = qq!* !; + + diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 097d38204..2e58315d4 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -27,8 +27,7 @@ $cgi->param('tax','') unless defined $cgi->param('tax'); $cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] ); -#my $payby = $cgi->param('payby'); -my $payby = $cgi->param('select'); # XXX key +my $payby = $cgi->param('payby'); my %noauto = ( 'CARD' => 'DCRD', @@ -37,8 +36,6 @@ my %noauto = ( $payby = $noauto{$payby} if ! $cgi->param('payauto') && exists $noauto{$payby}; -$cgi->param('payby', $payby); - if ( $payby ) { if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) { $cgi->param('payinfo', @@ -93,34 +90,39 @@ $new->setfield('paid', $cgi->param('paid') ) if $cgi->param('paid'); #perhaps this stuff should go to cust_main.pm -my $cust_pkg = ''; -my $svc_acct = ''; if ( $new->custnum eq '' ) { + my $cust_pkg = ''; + my $svc; + if ( $cgi->param('pkgpart_svcpart') ) { + my $x = $cgi->param('pkgpart_svcpart'); $x =~ /^(\d+)_(\d+)$/ or die "illegal pkgpart_svcpart $x\n"; my($pkgpart, $svcpart) = ($1, $2); + my $part_pkg = qsearchs('part_pkg', { 'pkgpart' => $pkgpart } ); #false laziness: copied from FS::cust_pkg::order (which should become a #FS::cust_main method) my(%part_pkg); # generate %part_pkg # $part_pkg{$pkgpart} is true iff $custnum may purchase $pkgpart my $agent = qsearchs('agent',{'agentnum'=> $new->agentnum }); - #my($type_pkgs); - #foreach $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) { - # my($pkgpart)=$type_pkgs->pkgpart; - # $part_pkg{$pkgpart}++; - #} - # $pkgpart_href->{PKGPART} is true iff $custnum may purchase $pkgpart - my $pkgpart_href = $agent->pkgpart_hashref; - #eslaf - - # this should wind up in FS::cust_pkg! - $error ||= "Agent ". $new->agentnum. " (type ". $agent->typenum. ") can't ". - "purchase pkgpart ". $pkgpart - #unless $part_pkg{ $pkgpart }; - unless $pkgpart_href->{ $pkgpart }; + + if ( $agent ) { + # $pkgpart_href->{PKGPART} is true iff $custnum may purchase $pkgpart + my $pkgpart_href = $agent->pkgpart_hashref + if $agent; + #eslaf + + # this should wind up in FS::cust_pkg! + $error ||= "Agent ". $new->agentnum. " (type ". $agent->typenum. + ") can't purchase pkgpart ". $pkgpart + #unless $part_pkg{ $pkgpart }; + unless $pkgpart_href->{ $pkgpart } + || $agent->agentnum == $part_pkg->agentnum; + } else { + $error = 'Select agent'; + } $cust_pkg = new FS::cust_pkg ( { #later 'custnum' => $custnum, @@ -132,32 +134,49 @@ if ( $new->custnum eq '' ) { #$error ||= $cust_svc->check; - my %svc_acct = ( - 'svcpart' => $svcpart, - 'username' => $cgi->param('username'), - '_password' => $cgi->param('_password'), - 'popnum' => $cgi->param('popnum'), - ); - $svc_acct{'domsvc'} = $cgi->param('domsvc') - if $cgi->param('domsvc'); + my $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } ); + my $svcdb = $part_svc->svcdb; + + if ( $svcdb eq 'svc_acct' ) { + + my %svc_acct = ( + 'svcpart' => $svcpart, + 'username' => scalar($cgi->param('username')), + '_password' => scalar($cgi->param('_password')), + 'popnum' => scalar($cgi->param('popnum')), + ); + $svc_acct{'domsvc'} = $cgi->param('domsvc') + if $cgi->param('domsvc'); + + $svc = new FS::svc_acct \%svc_acct; + + #and just in case you were silly + $svc->svcpart($svcpart); + $svc->username($cgi->param('username')); + $svc->_password($cgi->param('_password')); + $svc->popnum($cgi->param('popnum')); + + } elsif ( $svcdb eq 'svc_phone' ) { + + my %svc_phone = ( + 'svcpart' => $svcpart, + map { $_ => scalar($cgi->param($_)) } + qw( countrycode phonenum sip_password pin phone_name ) + ); - $svc_acct = new FS::svc_acct \%svc_acct; + $svc = new FS::svc_phone \%svc_phone; - #and just in case you were silly - $svc_acct->svcpart($svcpart); - $svc_acct->username($cgi->param('username')); - $svc_acct->_password($cgi->param('_password')); - $svc_acct->popnum($cgi->param('popnum')); + } else { + die "$svcdb not handled on new customer yet"; + } #$error ||= $svc_acct->check; - } elsif ( $cgi->param('username') ) { #good thing to catch - $error = "Can't assign username without a package!"; } use Tie::RefHash; tie my %hash, 'Tie::RefHash'; - %hash = ( $cust_pkg => [ $svc_acct ] ) if $cust_pkg; + %hash = ( $cust_pkg => [ $svc ] ) if $cust_pkg; $error ||= $new->insert( \%hash, \@invoicing_list ); my $conf = new FS::Conf; diff --git a/httemplate/elements/select-domain.html b/httemplate/elements/select-domain.html index a9998da06..3372e068f 100644 --- a/httemplate/elements/select-domain.html +++ b/httemplate/elements/select-domain.html @@ -7,7 +7,7 @@ ' LEFT JOIN cust_pkg USING ( pkgnum ) '. ' LEFT JOIN cust_main USING ( custnum ) ', 'agent_virt' => 1, - 'agent_null-right' => 'View/link unlinked services', + 'agent_null_right' => 'View/link unlinked services', @_, ) %> diff --git a/httemplate/elements/select-svc_acct-domain.html b/httemplate/elements/select-svc_acct-domain.html new file mode 100644 index 000000000..c9a920636 --- /dev/null +++ b/httemplate/elements/select-svc_acct-domain.html @@ -0,0 +1,46 @@ + +<%init> + +my %opt = @_; + +my $domsvc = $opt{'curr_value'}; +my $part_svc = $opt{'part_svc'} + || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} }); + +#optional +my $cust_pkg = $opt{'cust_pkg'}; +$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} }) + if $opt{'pkgnum'}; + +my $pkgnum = $cust_pkg ? $cust_pkg->pkgnum : ''; + +my %svc_domain = (); + +if ( $domsvc ) { + my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $domsvc } ); + if ( $svc_domain ) { + $svc_domain{$svc_domain->svcnum} = $svc_domain; + } else { + warn "unknown svc_domain.svcnum for svc_acct.domsvc: $domsvc"; + } +} + +%svc_domain = ( + %svc_domain, + FS::svc_acct->domain_select_hash( 'svcpart' => $part_svc->svcpart, + 'pkgnum' => $pkgnum, + ) +); + diff --git a/httemplate/elements/selectlayers.html b/httemplate/elements/selectlayers.html index 82f5dd1a7..a85cea193 100644 --- a/httemplate/elements/selectlayers.html +++ b/httemplate/elements/selectlayers.html @@ -63,18 +63,29 @@ Example: @@ -124,10 +134,16 @@ Example: % % unless ( grep $opt{$_}, qw(js_only select_only) ) { -% foreach my $layer ( keys %$options ) { +% foreach my $layer ( @layers ) { +% my $selected_layer; +% if ( $opt{layermap} ) { +% $selected_layer = $opt{layermap}->{$selected}; +% } else { +% $selected_layer = $selected; +% }
" @@ -162,6 +178,14 @@ tie my %options, 'Tie::IxHash', my $between = exists($opt{html_between}) ? $opt{html_between} : ''; my $options = \%options; +my @layers = (); +if ( $opt{layermap} ) { + my %layers = map { $opt{layermap}->{$_} => 1 } keys %options; + @layers = keys %layers; +} else { + @layers = keys %options; +} + my $selected = exists($opt{curr_value}) ? $opt{curr_value} : ''; #XXX eek. also eek $layer_fields in the layer_callback() call... diff --git a/httemplate/misc/part_svc-columns.cgi b/httemplate/misc/part_svc-columns.cgi new file mode 100644 index 000000000..060256154 --- /dev/null +++ b/httemplate/misc/part_svc-columns.cgi @@ -0,0 +1,13 @@ +<% objToJson(\@output) %> +<%init> + +my $conf = new FS::Conf; + +my $pkgpart_svcpart = $cgi->param('arg'); +$pkgpart_svcpart =~ /^\d+_(\d+)$/; +my $part_svc = qsearchs('part_svc', { 'svcpart' => $1 }) if $1; + +my @output = map { ( $_->columnname, $_->columnflag, $_->columnvalue ) } + $part_svc->all_part_svc_column; + + -- cgit v1.2.1 From 90fecad861bd6817b55e9391431430e0d86d9084 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 12 Apr 2009 06:24:45 +0000 Subject: adding --- httemplate/elements/tr-select-svc_acct-domain.html | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 httemplate/elements/tr-select-svc_acct-domain.html diff --git a/httemplate/elements/tr-select-svc_acct-domain.html b/httemplate/elements/tr-select-svc_acct-domain.html new file mode 100644 index 000000000..9d1a4b678 --- /dev/null +++ b/httemplate/elements/tr-select-svc_acct-domain.html @@ -0,0 +1,34 @@ +%if ( $columnflag eq 'F' ) { + +% } else { + + + <% $opt{'label'} || 'Domain' %> + + <% include('/elements/select-svc_acct-domain.html', + 'curr_value' => $domsvc, + 'part_svc' => $part_svc, + 'cust_pkg' => $cust_pkg, + ) + %> + + +% } +<%init> + +my %opt = @_; + +my $domsvc = $opt{'curr_value'}; + +#required +my $part_svc = $opt{'part_svc'} + || qsearchs('part_svc', { 'svcpart' => $opt{'svcpart'} }); + +my $columnflag = $part_svc->part_svc_column('domsvc')->columnflag; + +#optional +my $cust_pkg = $opt{'cust_pkg'}; +$cust_pkg ||= qsearchs('cust_pkg', { 'pkgnum' => $opt{'pkgnum'} }) + if $opt{'pkgnum'}; + + -- cgit v1.2.1 From a640ee92f7a90fffc1060bf0d499a83ddae4fc2c Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 13 Apr 2009 23:37:08 +0000 Subject: debugging --- FS/FS/cust_main.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index b828542a7..9aac1db7b 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2459,6 +2459,7 @@ sub bill { foreach my $tax ( keys %taxlisthash ) { my $tax_object = shift @{ $taxlisthash{$tax} }; warn "found ". $tax_object->taxname. " as $tax\n" if $DEBUG > 2; + warn " ". join('/', @{ $taxlisthash{$tax} } ). "\n" if $DEBUG > 2; my $hashref_or_error = $tax_object->taxline( $taxlisthash{$tax}, 'custnum' => $self->custnum, -- cgit v1.2.1 From 470bbdfd0bf8c62a1b7ff124bc18ba718ab0c628 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 14 Apr 2009 00:09:31 +0000 Subject: add configuration option to control recurring_flag behavior, RT#3843 --- FS/FS/Conf.pm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 9d8c3f20e..6403fb7bc 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1660,6 +1660,17 @@ worry that config_items is freeside-specific and icky. 'type' => 'text', }, + { + 'key' => 'credit_card-recurring_billing_flag', + 'section' => 'billing', + 'description' => 'This controls when the system passes the "recurring_billing" flag on credit card transactions. If supported by your processor (and the Business::OnlinePayment processor module), passing the flag indicates this is a recurring transaction and may turn off the CVV requirement. ', + 'type' => 'select', + 'select_hash' => [ + 'actual_oncard' => 'Default/classic behavior: set the flag if a customer has actual previous charges on the card.', + 'transaction_is_recur' => 'Set the flag if the transaction itself is recurring, irregardless of previous charges on the card.', + ], + }, + { 'key' => 'cvv-save', 'section' => 'billing', -- cgit v1.2.1 From 1442c00818afaf86855090126c5f9bfbf8242d77 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 14 Apr 2009 16:12:54 +0000 Subject: better at least --- httemplate/misc/process/tax-import.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/misc/process/tax-import.cgi b/httemplate/misc/process/tax-import.cgi index 016d4b60c..537af490f 100644 --- a/httemplate/misc/process/tax-import.cgi +++ b/httemplate/misc/process/tax-import.cgi @@ -2,7 +2,7 @@ <%init> die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Resend invoices'); + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); my $server = new FS::UI::Web::JSRPC 'FS::tax_rate::process_batch_import', $cgi; -- cgit v1.2.1 From 437f7374ed17088113c4067df42201295b6d6c43 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 14 Apr 2009 16:14:48 +0000 Subject: hmmm --- httemplate/misc/process/tax-import.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/misc/process/tax-import.cgi b/httemplate/misc/process/tax-import.cgi index 537af490f..f800dbd5b 100644 --- a/httemplate/misc/process/tax-import.cgi +++ b/httemplate/misc/process/tax-import.cgi @@ -2,7 +2,7 @@ <%init> die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + unless $FS::CurrentUser::CurrentUser->access_right('Import'); my $server = new FS::UI::Web::JSRPC 'FS::tax_rate::process_batch_import', $cgi; -- cgit v1.2.1 From 8c804ba59c8b284e1294e9928b5412fdf31e412c Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 14 Apr 2009 17:16:16 +0000 Subject: add configuration option to control recurring_flag behavior, RT#3843 --- FS/FS/Conf.pm | 7 +++ FS/FS/Schema.pm | 1 + FS/FS/agent.pm | 15 ++++-- FS/FS/cust_main.pm | 154 +++++++++++++++++++++++++++++++++++++---------------- 4 files changed, 125 insertions(+), 52 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 6403fb7bc..7be0dd0ca 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1671,6 +1671,13 @@ worry that config_items is freeside-specific and icky. ], }, + { + 'key' => 'credit_card-recurring_billing_acct_code', + 'section' => 'billing', + 'description' => 'When the "recurring billing" flag is set, also set the "acct_code" to "rebill". Useful for reporting purposes with supported gateways (PlugNPay, others?)', + 'type' => 'checkbox', + }, + { 'key' => 'cvv-save', 'section' => 'billing', diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index e4076b13d..c7bbf614c 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -847,6 +847,7 @@ sub tables_hashref { 'payinfo', 'varchar', 'NULL', 512, '', '', #see cust_main above 'paymask', 'varchar', 'NULL', $char_d, '', '', 'paydate', 'varchar', 'NULL', 10, '', '', + 'recurring_billing', 'varchar', 'NULL', $char_d, '', '', #'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes. 'payunique', 'varchar', 'NULL', $char_d, '', '', #separate paybatch "unique" functions from current usage diff --git a/FS/FS/agent.pm b/FS/FS/agent.pm index e471e04a5..5fbe2c46d 100644 --- a/FS/FS/agent.pm +++ b/FS/FS/agent.pm @@ -225,16 +225,21 @@ sub payment_gateway { my $taxclass = ''; if ( $options{invnum} ) { + my $cust_bill = qsearchs('cust_bill', { 'invnum' => $options{invnum} } ); die "invnum ". $options{'invnum'}. " not found" unless $cust_bill; - my @taxclasses = - map { $_->part_pkg->taxclass } + + my @part_pkg = + map { $_->part_pkg } grep { $_ } map { $_->cust_pkg } $cust_bill->cust_bill_pkg; - unless ( grep { $taxclasses[0] ne $_ } @taxclasses ) { #unless there are - #different taxclasses $taxclass = $taxclasses[0]; - } + + my @taxclasses = map $_->taxclass, @part_pkg; + + $taxclass = $taxclasses[0] + unless grep { $taxclasses[0] ne $_ } @taxclasses; #unless there are + #different taxclasses } #look for an agent gateway override first diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 9aac1db7b..a62987b32 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3503,24 +3503,35 @@ sub realtime_bop { return "Banned credit card" if $ban; ### - # select a gateway + # set taxclass and trans_is_recur based on invnum if there is one ### my $taxclass = ''; + my $trans_is_recur = 0; if ( $options{'invnum'} ) { + my $cust_bill = qsearchs('cust_bill', { 'invnum' => $options{'invnum'} } ); die "invnum ". $options{'invnum'}. " not found" unless $cust_bill; - my @taxclasses = - map { $_->part_pkg->taxclass } + + my @part_pkg = + map { $_->part_pkg } grep { $_ } map { $_->cust_pkg } $cust_bill->cust_bill_pkg; - unless ( grep { $taxclasses[0] ne $_ } @taxclasses ) { #unless there are - #different taxclasses - $taxclass = $taxclasses[0]; - } + + my @taxclasses = map $_->taxclass, @part_pkg; + $taxclass = $taxclasses[0] + unless grep { $taxclasses[0] ne $_ } @taxclasses; #unless there are + #different taxclasses + $trans_is_recur = 1 + if grep { $_->freq ne '0' } @part_pkg; + } + ### + # select a gateway + ### + #look for an agent gateway override first my $cardtype; if ( $method eq 'CC' ) { @@ -3648,16 +3659,15 @@ sub realtime_bop { : $self->payissue; $content{issue_number} = $payissue if $payissue; - $content{recurring_billing} = 'YES' - if qsearch('cust_pay', { 'custnum' => $self->custnum, - 'payby' => 'CARD', - 'payinfo' => $payinfo, - } ) - || qsearch('cust_pay', { 'custnum' => $self->custnum, - 'payby' => 'CARD', - 'paymask' => $self->mask_payinfo('CARD', $payinfo), - } ); - + if ( $self->_bop_recurring_billing( 'payinfo' => $payinfo, + 'trans_is_recur' => $trans_is_recur, + ) + ) + { + $content{recurring_billing} = 'YES'; + $content{acct_code} = 'rebill' + if $conf->exists('credit_card-recurring_billing_acct_code'); + } } elsif ( $method eq 'ECHECK' ) { ( $content{account_number}, $content{routing_code} ) = @@ -3716,15 +3726,16 @@ sub realtime_bop { #okay, good to go, if we're a duplicate, cust_pay_pending will kick us out my $cust_pay_pending = new FS::cust_pay_pending { - 'custnum' => $self->custnum, - #'invnum' => $options{'invnum'}, - 'paid' => $amount, - '_date' => '', - 'payby' => $method2payby{$method}, - 'payinfo' => $payinfo, - 'paydate' => $paydate, - 'status' => 'new', - 'gatewaynum' => ( $payment_gateway ? $payment_gateway->gatewaynum : '' ), + 'custnum' => $self->custnum, + #'invnum' => $options{'invnum'}, + 'paid' => $amount, + '_date' => '', + 'payby' => $method2payby{$method}, + 'payinfo' => $payinfo, + 'paydate' => $paydate, + 'recurring_billing' => $content{recurring_billing}, + 'status' => 'new', + 'gatewaynum' => ( $payment_gateway ? $payment_gateway->gatewaynum : '' ), }; $cust_pay_pending->payunique( $options{payunique} ) if defined($options{payunique}) && length($options{payunique}); @@ -4010,6 +4021,34 @@ sub realtime_bop { } +sub _bop_recurring_billing { + my( $self, %opt ) = @_; + + my $method = $conf->config('credit_card-recurring_billing_flag'); + + if ( $method eq 'transaction_is_recur' ) { + + return 1 if $opt{'trans_is_recur'}; + + } else { + + my %hash = ( 'custnum' => $self->custnum, + 'payby' => 'CARD', + ); + + return 1 + if qsearch('cust_pay', { %hash, 'payinfo' => $opt{'payinfo'} } ) + || qsearch('cust_pay', { %hash, 'paymask' => $self->mask_payinfo('CARD', + $opt{'payinfo'} ) + } ); + + } + + return 0; + +} + + =item realtime_refund_bop METHOD [ OPTION => VALUE ... ] Refunds a realtime credit card, ACH (electronic check) or phone bill transaction @@ -4561,6 +4600,27 @@ sub _new_realtime_bop { $self->_bop_defaults(\%options); + ### + # set trans_is_recur based on invnum if there is one + ### + + my $trans_is_recur = 0; + if ( $options{'invnum'} ) { + + my $cust_bill = qsearchs('cust_bill', { 'invnum' => $options{'invnum'} } ); + die "invnum ". $options{'invnum'}. " not found" unless $cust_bill; + + my @part_pkg = + map { $_->part_pkg } + grep { $_ } + map { $_->cust_pkg } + $cust_bill->cust_bill_pkg; + + $trans_is_recur = 1 + if grep { $_->freq ne '0' } @part_pkg; + + } + ### # select a gateway ### @@ -4637,16 +4697,15 @@ sub _new_realtime_bop { : $self->payissue; $content{issue_number} = $payissue if $payissue; - $content{recurring_billing} = 'YES' - if qsearch('cust_pay', { 'custnum' => $self->custnum, - 'payby' => 'CARD', - 'payinfo' => $options{payinfo}, - } ) - || qsearch('cust_pay', { 'custnum' => $self->custnum, - 'payby' => 'CARD', - 'paymask' => $self->mask_payinfo('CARD', $options{payinfo}), - } ); - + if ( $self->_bop_recurring_billing( 'payinfo' => $options{'payinfo'}, + 'trans_is_recur' => $trans_is_recur, + ) + ) + { + $content{recurring_billing} = 'YES'; + $content{acct_code} = 'rebill' + if $conf->exists('credit_card-recurring_billing_acct_code'); + } } elsif ( $namespace eq 'Business::OnlinePayment' && $options{method} eq 'ECHECK' ){ ( $content{account_number}, $content{routing_code} ) = @@ -4708,17 +4767,18 @@ sub _new_realtime_bop { #okay, good to go, if we're a duplicate, cust_pay_pending will kick us out my $cust_pay_pending = new FS::cust_pay_pending { - 'custnum' => $self->custnum, - #'invnum' => $options{'invnum'}, - 'paid' => $options{amount}, - '_date' => '', - 'payby' => $bop_method2payby{$options{method}}, - 'payinfo' => $options{payinfo}, - 'paydate' => $paydate, - 'status' => 'new', - 'gatewaynum' => $payment_gateway->gatewaynum || '', - 'session_id' => $options{session_id} || '', - 'jobnum' => $options{depend_jobnum} || '', + 'custnum' => $self->custnum, + #'invnum' => $options{'invnum'}, + 'paid' => $options{amount}, + '_date' => '', + 'payby' => $bop_method2payby{$options{method}}, + 'payinfo' => $options{payinfo}, + 'paydate' => $paydate, + 'recurring_billing' => $content{recurring_billing}, + 'status' => 'new', + 'gatewaynum' => $payment_gateway->gatewaynum || '', + 'session_id' => $options{session_id} || '', + 'jobnum' => $options{depend_jobnum} || '', }; $cust_pay_pending->payunique( $options{payunique} ) if defined($options{payunique}) && length($options{payunique}); -- cgit v1.2.1 From a5bf104f1fb29ea6e3fa6993dd60069e3d2cfca7 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 14 Apr 2009 20:27:50 +0000 Subject: don't hide old packages that have services, RT#5179 --- httemplate/view/cust_main/packages.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index d55560f34..0da82500a 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -177,8 +177,11 @@ sub get_packages { join(', ', map "cust_pkg.$_", fields('cust_pkg') ). ', '. join(', ', map "part_pkg.$_", fields('part_pkg') ); + my $num_svcs = '( SELECT COUNT(*) FROM cust_svc '. + ' WHERE cust_svc.pkgnum = cust_pkg.pkgnum ) AS num_svcs'; + my @packages = $cust_main->$method( { - 'select' => "$cust_pkg_fields, $part_pkg_fields", + 'select' => "$cust_pkg_fields, $part_pkg_fields, $num_svcs", 'addl_from' => 'LEFT JOIN part_pkg USING ( pkgpart )', } ); my $num_old_packages = scalar(@packages); @@ -200,7 +203,9 @@ sub get_packages { ); @packages = - grep { !exists($hide{$_->status}) or $_->get($hide{$_->status}) > $then } + grep { !exists($hide{$_->status}) or $_->get($hide{$_->status}) > $then + or $_->num_svcs #don't hide packages w/services + } @packages; } -- cgit v1.2.1 From 554a8168de9871b6085fe36ce5d86f3681421c64 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 14 Apr 2009 21:01:40 +0000 Subject: remove debugging --- httemplate/view/cust_main/packages.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 0da82500a..ed98ba903 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -76,7 +76,7 @@ Current packages Services -% $FS::cust_pkg::DEBUG = 2; +% #$FS::cust_pkg::DEBUG = 2; % foreach my $cust_pkg (@$packages) { % % if ( $bgcolor eq $bgcolor1 ) { -- cgit v1.2.1 From dae1709465dafbd941ffd326117bc59b898352df Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Apr 2009 02:15:45 +0000 Subject: this should fix credits pushing typeset invoices off the right --- FS/FS/cust_bill.pm | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 77f0dd30f..408da9930 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -2281,6 +2281,7 @@ sub print_generic { # credits my $credittotal = 0; foreach my $credit ( $self->_items_credits ) { + my $total; $total->{'total_item'} = &$escape_function($credit->{'description'}); $credittotal += $credit->{'amount'}; @@ -2297,26 +2298,15 @@ sub print_generic { product_code => '', section => $adjust_section, }; - }else{ + } else { push @total_items, $total; } + + push @buf, [ $credit->{'description'}, $money_char.$credit->{'amount'} ]; + } $invoice_data{'credittotal'} = sprintf('%.2f', $credittotal); - # credits (again) - foreach ( $self->cust_credited ) { - - #something more elaborate if $_->amount ne $_->cust_credit->credited ? - - my $reason = substr($_->cust_credit->reason,0,32); - $reason .= '...' if length($reason) < length($_->cust_credit->reason); - $reason = " ($reason) " if $reason; - push @buf,[ - "Credit #". $_->crednum. " (". time2str("%x",$_->cust_credit->_date) .")". $reason, - $money_char. sprintf("%10.2f",$_->amount) - ]; - } - # payments my $paymenttotal = 0; foreach my $payment ( $self->_items_payments ) { @@ -2936,10 +2926,10 @@ sub _items_credits { #something more elaborate if $_->amount ne $_->cust_credit->credited ? - my $reason = $_->cust_credit->reason; - #my $reason = substr($_->cust_credit->reason,0,32); - #$reason .= '...' if length($reason) < length($_->cust_credit->reason); + my $reason = substr($_->cust_credit->reason,0,32); + $reason .= '...' if length($reason) < length($_->cust_credit->reason); $reason = " ($reason) " if $reason; + push @b, { #'description' => 'Credit ref\#'. $_->crednum. # " (". time2str("%x",$_->cust_credit->_date) .")". @@ -2949,12 +2939,6 @@ sub _items_credits { 'amount' => sprintf("%.2f",$_->amount), }; } - #foreach ( @cr_cust_credit ) { - # push @buf,[ - # "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")", - # $money_char. sprintf("%10.2f",$_->credited) - # ]; - #} @b; -- cgit v1.2.1 From 4cd4bc31a0ceb17ac9e8b0162450dd26f315a4fd Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Apr 2009 02:29:36 +0000 Subject: show 60 chars on typeset invoices but only 32 on plaintext, RT#3905 --- FS/FS/cust_bill.pm | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 408da9930..071b89cd0 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -2280,7 +2280,7 @@ sub print_generic { # credits my $credittotal = 0; - foreach my $credit ( $self->_items_credits ) { + foreach my $credit ( $self->_items_credits('trim_len'=>60) ) { my $total; $total->{'total_item'} = &$escape_function($credit->{'description'}); @@ -2302,10 +2302,13 @@ sub print_generic { push @total_items, $total; } - push @buf, [ $credit->{'description'}, $money_char.$credit->{'amount'} ]; - } $invoice_data{'credittotal'} = sprintf('%.2f', $credittotal); + + #credits (again) + foreach my $credit ( $self->_items_credits('trim_len'=>32) ) { + push @buf, [ $credit->{'description'}, $money_char.$credit->{'amount'} ]; + } # payments my $paymenttotal = 0; @@ -2918,7 +2921,8 @@ sub _items_cust_bill_pkg { } sub _items_credits { - my $self = shift; + my( $self, %opt ) = @_; + my $trim_len = $opt{'trim_len'} || 60; my @b; #credits @@ -2926,7 +2930,7 @@ sub _items_credits { #something more elaborate if $_->amount ne $_->cust_credit->credited ? - my $reason = substr($_->cust_credit->reason,0,32); + my $reason = substr($_->cust_credit->reason, 0, $trim_len); $reason .= '...' if length($reason) < length($_->cust_credit->reason); $reason = " ($reason) " if $reason; -- cgit v1.2.1 From 48fdda923dd0c3227190da57ad0fca704725fb43 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Apr 2009 02:44:11 +0000 Subject: fix 1.7->1.9 upgrade glitch with self-service where process_payment required "payby" instead of defaulting to CARD, RT#3905 --- FS/FS/ClientAPI/MyAccount.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 564acb1a6..d64c72c0e 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -451,6 +451,7 @@ sub process_payment { or return { 'error' => gettext('illegal_text'). " paybatch: ". $p->{'paybatch'} }; my $paybatch = $1; + $p->{'payby'} ||= 'CARD'; $p->{'payby'} =~ /^([A-Z]{4})$/ or return { 'error' => "illegal_payby " . $p->{'payby'} }; my $payby = $1; -- cgit v1.2.1 From ba176b6005c1c09cfd00c57befe72ba9561b77f8 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Apr 2009 05:52:09 +0000 Subject: s/GECOS/Real Name/ RT#3519 --- 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 e87a8ee9a..6a47ec767 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -214,7 +214,7 @@ Service #<% $svcnum %> % if ($svc_acct->finger ne '') { - GECOS + Real Name <% $svc_acct->finger %> % } -- cgit v1.2.1 From 9f5e5a6ef0aa20bafb200c0bfa9678bbccda127b Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 15 Apr 2009 07:14:11 +0000 Subject: should fix view of unlinked phone numbers, RT#5171 --- httemplate/view/elements/svc_Common.html | 55 ++++++++++++++++++-------------- httemplate/view/svc_Common.html | 12 +++---- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html index a0b4e37b2..125fcd0b8 100644 --- a/httemplate/view/elements/svc_Common.html +++ b/httemplate/view/elements/svc_Common.html @@ -1,30 +1,40 @@ -% # options example... -% # -% # 'table' => 'svc_something' -% # -% # 'labels' => { -% # 'column' => 'Label', -% # }, -% # -% # listref - each item is a literal column name (or method) or (notyet) coderef -% # if not specified all columns (except for the primary key) will be viewable -% # 'fields' => [ -% # ] -% # -% # # defaults to "edit/$table.cgi?", will have svcnum appended -% # 'edit_url' => -% -% -% if ( $custnum ) { +<%doc> + +#Example: + + include( 'elements/svc_Common.html, + 'table' => 'svc_something' + + 'labels' => { + 'column' => 'Label', + }, + + #listref - each item is a literal column name (or method) or + # (notyet) coderef. if not specified all columns (except for the + #primary key) will be viewable + 'fields' => [ + ] + + # defaults to "edit/$table.cgi?", will have svcnum appended + 'edit_url' => + ) + + +% if ( $custnum ) { <% include("/elements/header.html","View $label: $value") %> <% include( '/elements/small_custview.html', $custnum, '', 1, "${p}view/cust_main.cgi") %>
+ % } else { + <% include("/elements/header.html","View $label: $value", menubar( + "Cancel this (unaudited) $label" => + "javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')" + )) %> - <% include("/elements/header.html","View $label: $value", menubar( - "Cancel this (unaudited) $label" => - "javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')" - )) %> % } - Service #<% $svcnum %> % my $url = $opt{'edit_url'} || $p. 'edit/'. $opt{'table'}. '.cgi?'; | Edit this <% $label %> @@ -130,7 +135,9 @@ my $svc_x = qsearchs({ ' LEFT JOIN cust_pkg USING ( pkgnum ) '. ' LEFT JOIN cust_main USING ( custnum ) ', 'hashref' => { 'svcnum' => $svcnum }, - 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( + 'null_right' => 'View/link unlinked services' + ), }) or die "Unknown svcnum $svcnum in ". $opt{'table'}. " table\n"; my $cust_svc = $svc_x->cust_svc; diff --git a/httemplate/view/svc_Common.html b/httemplate/view/svc_Common.html index bb3a6dd33..defbee974 100644 --- a/httemplate/view/svc_Common.html +++ b/httemplate/view/svc_Common.html @@ -1,3 +1,9 @@ +<% include('elements/svc_Common.html', + 'table' => $table, + 'edit_url' => $p."edit/svc_Common.html?svcdb=$table;svcnum=", + %opt, + ) +%> <%init> # false laziness w/edit/svc_Common.html @@ -21,9 +27,3 @@ if ( UNIVERSAL::can("FS::$table", 'table_info') ) { } -<% include('elements/svc_Common.html', - 'table' => $table, - 'edit_url' => $p."edit/svc_Common.html?svcdb=$table;svcnum=", - %opt, - ) -%> -- cgit v1.2.1 From 05e3975829f4f6497d1e0aba4aea4d119759c09b Mon Sep 17 00:00:00 2001 From: rsiddall Date: Thu, 16 Apr 2009 03:58:20 +0000 Subject: More fixes for SuSE self-service: 1/ Put binaries in the right folder 2/ Make sure freeside group is created 3/ Make sure freeside home directory is created --- rpm/freeside.spec | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/rpm/freeside.spec b/rpm/freeside.spec index 77b506147..306008924 100644 --- a/rpm/freeside.spec +++ b/rpm/freeside.spec @@ -144,6 +144,7 @@ perl -ni -e 'print if !/\s+chown\s+/;' Makefile # Fix-ups for self-service. Should merge this into Makefile perl -pi -e 's|/usr/local/sbin|%{_sbindir}|g' FS/bin/freeside-selfservice-server perl -pi -e 's|/usr/local/bin|%{_bindir}|g' fs_selfservice/FS-SelfService/Makefile.PL +perl -pi -e 's|/usr/local/sbin|%{_sbindir}|g' fs_selfservice/FS-SelfService/Makefile.PL perl -pi -e 's|/usr/local/freeside|%{freeside_socket}|g' fs_selfservice/FS-SelfService/*.pm perl -pi -e 's|socket\s*=\s*"/usr/local/freeside|socket = "%{freeside_socket}|g' fs_selfservice/FS-SelfService/freeside-selfservice-* perl -pi -e 's|log_file\s*=\s*"/usr/local/freeside|log_file = "%{freeside_log}|g' fs_selfservice/FS-SelfService/freeside-selfservice-* @@ -329,27 +330,42 @@ cd ../.. %pre if ! %{__id} freeside &>/dev/null; then - /usr/sbin/useradd freeside +%if "%{_vendor}" == "suse" + /usr/sbin/groupadd freeside +%endif + /usr/sbin/useradd -m freeside fi %pre mason if ! %{__id} freeside &>/dev/null; then - /usr/sbin/useradd freeside +%if "%{_vendor}" == "suse" + /usr/sbin/groupadd freeside +%endif + /usr/sbin/useradd -m freeside fi %pre postgresql if ! %{__id} freeside &>/dev/null; then - /usr/sbin/useradd freeside +%if "%{_vendor}" == "suse" + /usr/sbin/groupadd freeside +%endif + /usr/sbin/useradd -m freeside fi %pre mysql if ! %{__id} freeside &>/dev/null; then - /usr/sbin/useradd freeside +%if "%{_vendor}" == "suse" + /usr/sbin/groupadd freeside +%endif + /usr/sbin/useradd -m freeside fi %pre selfservice-cgi if ! %{__id} freeside &>/dev/null; then - /usr/sbin/useradd freeside +%if "%{_vendor}" == "suse" + /usr/sbin/groupadd freeside +%endif + /usr/sbin/useradd -m freeside fi %post -- cgit v1.2.1 From caa6c563bd570fc53f333589bc95bc7a570626d0 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 17 Apr 2009 01:17:40 +0000 Subject: add customer status to receivables report selection, hopefully help enet, RT#5187 --- httemplate/search/report_receivables.cgi | 9 +++++++++ httemplate/search/report_receivables.html | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/httemplate/search/report_receivables.cgi b/httemplate/search/report_receivables.cgi index 58d87fa53..c5ca45338 100755 --- a/httemplate/search/report_receivables.cgi +++ b/httemplate/search/report_receivables.cgi @@ -116,6 +116,15 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { push @where, "agentnum = $agentnum"; } +#status (false laziness w/cust_main::search_sql + +#prospect active inactive suspended cancelled +if ( grep { $cgi->param('status') eq $_ } FS::cust_main->statuses() ) { + my $method = $cgi->param('status'). '_sql'; + #push @where, $class->$method(); + push @where, FS::cust_main->$method(); +} + #here is the agent virtualization push @where, $FS::CurrentUser::CurrentUser->agentnums_sql; diff --git a/httemplate/search/report_receivables.html b/httemplate/search/report_receivables.html index 19b1ee7cc..1ebe08cb8 100755 --- a/httemplate/search/report_receivables.html +++ b/httemplate/search/report_receivables.html @@ -11,6 +11,11 @@ <% include( '/elements/tr-select-agent.html', 'disable_empty'=>0 ) %> + + <% include( '/elements/tr-select-cust_main-status.html', + 'label' => 'Customer Status' + ) + %> Customers -- cgit v1.2.1 From 465e3d31929f6002146367e1950e3d2b70190846 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 17 Apr 2009 07:03:02 +0000 Subject: hide service search unless user has "View customer services" ACL, RT#3478 --- httemplate/elements/header.html | 2 ++ rt/html/Elements/FreesideSvcSearch | 2 ++ 2 files changed, 4 insertions(+) diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html index 8e902f038..058756745 100644 --- a/httemplate/elements/header.html +++ b/httemplate/elements/header.html @@ -202,11 +202,13 @@ input.fsblackbuttonselected { +% if ( $curuser->access_right('View customer services') ) {

Advanced
+% } diff --git a/rt/html/Elements/FreesideSvcSearch b/rt/html/Elements/FreesideSvcSearch index 4a5942421..d68122da5 100644 --- a/rt/html/Elements/FreesideSvcSearch +++ b/rt/html/Elements/FreesideSvcSearch @@ -1,3 +1,4 @@ +% if ( $FS::CurrentUser::CurrentUser->access_right('View customer services') ) {
+ <%init> -- cgit v1.2.1 From b19bf30f0d745d20e5e4f0a8e47ce16a04b02dd9 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 2 May 2009 00:02:07 +0000 Subject: finish up useful agent stuff on the config editor: adding, deleting overrides too. also add a confirmation to override deletion from the agent browse page. RT#5218 --- httemplate/browse/agent.cgi | 2 +- httemplate/config/config-delete.cgi | 13 +++-- httemplate/config/config-process.cgi | 3 ++ httemplate/config/config-view.cgi | 95 ++++++++++++++++++++++++++++++++---- 4 files changed, 98 insertions(+), 15 deletions(-) diff --git a/httemplate/browse/agent.cgi b/httemplate/browse/agent.cgi index 36bac781c..3319c77b3 100755 --- a/httemplate/browse/agent.cgi +++ b/httemplate/browse/agent.cgi @@ -386,7 +386,7 @@ Unused - <% $override->name %> (delete) + <% $override->name %> (delete) % } diff --git a/httemplate/config/config-delete.cgi b/httemplate/config/config-delete.cgi index cdac434fa..ffeae7877 100644 --- a/httemplate/config/config-delete.cgi +++ b/httemplate/config/config-delete.cgi @@ -2,14 +2,19 @@ die "access denied\n" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -die "No configuration item specified (bad URL)!" unless $cgi->keywords; -my ($query) = $cgi->keywords; -$query =~ /^(\d+)$/; +$cgi->param('confnum') =~ /^(\d+)$/ or die "illegal or missing confnum"; my $confnum = $1; my $conf = qsearchs('conf', {'confnum' => $confnum}); die "Configuration not found!" unless $conf; $conf->delete; +my $redirect = popurl(2); +if ( $cgi->param('redirect') eq 'config_view' ) { + $redirect .= 'config/config-view.cgi?showagent=1#'. $conf->name; +} else { + $redirect .= 'browse/agent.cgi'; +} + -<% $cgi->redirect(popurl(2) . "browse/agent.cgi") %> +<% $cgi->redirect($redirect) %> diff --git a/httemplate/config/config-process.cgi b/httemplate/config/config-process.cgi index a5918c035..f8b64e86f 100644 --- a/httemplate/config/config-process.cgi +++ b/httemplate/config/config-process.cgi @@ -66,6 +66,9 @@ $conf->delete($_, $agentnum) foreach @delete; % my $n = 0; % foreach my $type ( ref($i->type) ? @{$i->type} : $i->type ) { var configCell = window.top.document.getElementById('<% $agentnum. $i->key. $n %>'); + if ( ! configCell ) { + window.top.location.reload(); + } //alert('found cell ' + configCell); % if ( $type eq 'textarea' % || $type eq 'editlist' diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index bb6a3ca0b..aca37f2ad 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -58,7 +58,22 @@ Click on a configuration value to change it. % #$height = % } % -% my @agents = $page_agent ? ( $page_agent ) : ( '', @all_agents ); +% my @agents = (); +% my @add_agents = (); +% if ( $page_agent ) { +% @agents = ( $page_agent ); +% } else { +% @agents = ( '' ); +% if ( $i->per_agent ) { +% foreach my $agent (@all_agents) { +% if ( defined(_config_agentonly($conf, $i->key, $agent->agentnum)) ) { +% push @agents, $agent; +% } else { +% push @add_agents, $agent; +% } +% } +% } +% } % % foreach my $agent ( @agents ) { % my $agentnum = $agent ? $agent->agentnum : ''; @@ -81,6 +96,10 @@ Click on a configuration value to change it. # if $cgi->param('showagent')? ) %>: <% $i->description %> +% if ( $agent && $cgi->param('showagent') ) { + (delete agent override) +% } + @@ -190,25 +209,81 @@ Click on a configuration value to change it. % } # foreach my $agentnum +% if ( @add_agents ) { + + + + + +% } #if @add_agents + % } # foreach my $i
+ + Add <% $i->key %> override for + <% include('/elements/select-agent.html', + 'agents' => \@add_agents, + 'empty_label' => 'Select agent', + 'onchange' => "agent_changed", + 'id' => 'agent_'. $i->key, + ) + %> + agent + +% my $agent_el = "document.getElementById('agent_". $i->key. "')"; + $width, + 'height' => $height, + 'actionlabel' => 'Enter configuration value', + ) + %>" + > + +


% } # foreach my $nav_section + + <%once> #should probably be a Conf method. what else would need to use it? -#not even us, apparantly... -# defined( _config_agentonly($conf, $i->key, $_->agentnum) ) -#sub _config_agentonly { -# my($self,$name,$agentnum)=@_; -# my $hashref = { 'name' => $name }; -# $hashref->{agentnum} = $agentnum; -# local $FS::Record::conf = undef; # XXX evil hack prevents recursion -# FS::Record::qsearchs('conf', $hashref); -#} +sub _config_agentonly { + my($self,$name,$agentnum)=@_; + my $hashref = { 'name' => $name }; + $hashref->{agentnum} = $agentnum; + local $FS::Record::conf = undef; # XXX evil hack prevents recursion + FS::Record::qsearchs('conf', $hashref); +} <%init> -- cgit v1.2.1 From 5bdd15fbc33d0e273e787a49bfdeb014cf83481d Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 2 May 2009 22:11:45 +0000 Subject: fix eps preview --- FS/FS/Misc/eps2png.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Misc/eps2png.pm b/FS/FS/Misc/eps2png.pm index c175b3be8..aa8e5729a 100644 --- a/FS/FS/Misc/eps2png.pm +++ b/FS/FS/Misc/eps2png.pm @@ -31,7 +31,7 @@ my $mono = 0; # produce BW images if non-zero my $format; # output format my $gs_format; # GS output type my $output; # output, defaults to STDOUT -my $antialias = 8; #4; # antialiasing +my $antialias = 4; # antialiasing my $DEF_width; # desired widht my $DEF_height; # desired height #my $DEF_width = 90; # desired widht -- cgit v1.2.1 From ae8f98d14eb70d671e808d41167ae6afb2ee7053 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 3 May 2009 00:40:50 +0000 Subject: confdiff --- bin/confdiff | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 bin/confdiff diff --git a/bin/confdiff b/bin/confdiff new file mode 100755 index 000000000..5b6af859e --- /dev/null +++ b/bin/confdiff @@ -0,0 +1,27 @@ +#!/usr/bin/perl + +use FS::UID qw(adminsuidsetup); +use FS::Conf; + +adminsuidsetup('ivan'); + +my $conf = new FS::Conf; + +my $file2 = pop @ARGV; +my $file1 = pop @ARGV; + +open(FILE1, ">/tmp/$file1") or die "can't open /tmp/$file1: $!"; +print FILE1 $conf->config($file1); +print FILE1 "\n"; +close FILE1 or die $!; + +open(FILE2, ">/tmp/$file2") or die "can't open /tmp/$file2: $!"; +print FILE2 $conf->config($file2); +print FILE2 "\n"; +close FILE2 or die $!; + +my @opt = @ARGV; + +system('diff', @opt, "/tmp/$file1", "/tmp/$file2"); + +#unlink("/tmp/$file1', "/tmp/$file2"); -- cgit v1.2.1 From 53cadf47dea115cf804d07beb58c7de67429873f Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 3 May 2009 01:11:50 +0000 Subject: add ability to remove suffix-ed config items, RT#5218 --- FS/FS/Conf.pm | 12 +++++++----- httemplate/config/config-delete.cgi | 4 +++- httemplate/config/config-view.cgi | 12 ++++++++++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index cf4c43908..d3bd81762 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -92,6 +92,7 @@ sub _usecompat { $compat->$method(@_); } +# needs a non _ name, called externally by config-view now (and elsewhere?) sub _config { my($self,$name,$agentnum)=@_; my $hashref = { 'name' => $name }; @@ -451,11 +452,12 @@ sub _orbase_items { die "don't know about $base items" unless $proto->key eq $base; map { new FS::ConfItem { - 'key' => $_, - 'section' => $proto->section, - 'description' => 'Alternate ' . $proto->description . ' See the billing documentation for details.', - 'type' => $proto->type, - }; + 'key' => $_, + 'base_key' => $proto->key, + 'section' => $proto->section, + 'description' => 'Alternate ' . $proto->description . ' See the billing documentation for details.', + 'type' => $proto->type, + }; } &$listmaker($base); } @base_items, ); diff --git a/httemplate/config/config-delete.cgi b/httemplate/config/config-delete.cgi index ffeae7877..a05cb1e14 100644 --- a/httemplate/config/config-delete.cgi +++ b/httemplate/config/config-delete.cgi @@ -10,8 +10,10 @@ die "Configuration not found!" unless $conf; $conf->delete; my $redirect = popurl(2); -if ( $cgi->param('redirect') eq 'config_view' ) { +if ( $cgi->param('redirect') eq 'config_view_showagent' ) { $redirect .= 'config/config-view.cgi?showagent=1#'. $conf->name; +} elsif ( $cgi->param('redirect') eq 'config_view' ) { + $redirect .= 'config/config-view.cgi'; } else { $redirect .= 'browse/agent.cgi'; } diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index aca37f2ad..9b5b13251 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -97,7 +97,16 @@ Click on a configuration value to change it. ) %>: <% $i->description %> % if ( $agent && $cgi->param('showagent') ) { - (delete agent override) +% my $confnum = +% _config_agentonly($conf, $i->key, $agent->agentnum)->confnum; + (delete agent override) +% } elsif ( $i->base_key ) { +% my $confnum = +% $agent +% ? _config_agentonly($conf, $i->key, $agent->agentnum)->confnum +% : $conf->_config( $i->key )->confnum; +% my $showagent = $cgi->param('showagent') ? '_showagent' : ''; + (delete configuration item) % } @@ -308,7 +317,6 @@ if ($cgi->param('agentnum') =~ /^(\d+)$/) { my $conf = new FS::Conf; my @config_items = grep { $page_agent ? $_->per_agent : 1 } - grep { $_->key != ~/^invoice_(html|latex|template)/ } $conf->config_items; my @sections = qw(required billing username password UI session shell BIND ); -- cgit v1.2.1 From e91ac7e6e069df321b815b08bf0e35d5fd3bd8f7 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 3 May 2009 01:45:09 +0000 Subject: add ability to delete invoice_latexreturnaddress and invoice_htmlreturnaddress too, RT#5218 --- httemplate/config/config-view.cgi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index 9b5b13251..c5ac1a685 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -100,7 +100,8 @@ Click on a configuration value to change it. % my $confnum = % _config_agentonly($conf, $i->key, $agent->agentnum)->confnum; (delete agent override) -% } elsif ( $i->base_key ) { +% } elsif ( $i->base_key +% || ( $deleteable{$i->key} && $conf->exists($i->key) ) ) { % my $confnum = % $agent % ? _config_agentonly($conf, $i->key, $agent->agentnum)->confnum @@ -319,6 +320,9 @@ my $conf = new FS::Conf; my @config_items = grep { $page_agent ? $_->per_agent : 1 } $conf->config_items; +my @deleteable = qw( invoice_latexreturnaddress invoice_htmlreturnaddress ); +my %deleteable = map { $_ => 1 } @deleteable; + my @sections = qw(required billing username password UI session shell BIND ); push @sections, '', 'deprecated'; -- cgit v1.2.1 From 6ff3e876504bab769ebf557cb5fd90ec52dfc3e7 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 3 May 2009 03:13:02 +0000 Subject: edit any config item --- httemplate/config/config.cgi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/httemplate/config/config.cgi b/httemplate/config/config.cgi index 7f2e6670d..8d5b1ae43 100644 --- a/httemplate/config/config.cgi +++ b/httemplate/config/config.cgi @@ -289,8 +289,7 @@ Setting <% $key %> <%once> my $conf = new FS::Conf; -my @config_items = grep { $_->key != ~/^invoice_(html|latex|template)/ } - $conf->config_items; +my @config_items = $conf->config_items; my %confitems = map { $_->key => $_ } @config_items; -- cgit v1.2.1 From d557c2a3bf895d17c7d9fcfa2f5fb0c99b9e989f Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 3 May 2009 18:34:09 +0000 Subject: add "Redownload resolved batches" ACL for s1, RT#4271 --- FS/FS/AccessRight.pm | 1 + httemplate/search/cust_pay_batch.cgi | 3 +++ 2 files changed, 4 insertions(+) diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index 93660e236..af480dfa7 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -221,6 +221,7 @@ tie my %rights, 'Tie::IxHash', { rightname=>'Time queue', global=>1 }, { rightname=>'Process batches', global=>1 }, { rightname=>'Reprocess batches', global=>1 }, + { rightname=>'Redownload resolved batches', global=>1 }, { rightname=>'Import', global=>1 }, #some of these are ag-virt'ed now? give em their own ACLs { rightname=>'Export', global=>1 }, { rightname=> 'Edit rating data', desc=>'Delete CDRs', global=>1 }, diff --git a/httemplate/search/cust_pay_batch.cgi b/httemplate/search/cust_pay_batch.cgi index 157696366..2fceb93f8 100755 --- a/httemplate/search/cust_pay_batch.cgi +++ b/httemplate/search/cust_pay_batch.cgi @@ -132,6 +132,9 @@ if ( $pay_batch ) { || ( $pay_batch->status eq 'I' && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches') ) + || ( $pay_batch->status eq 'R' + && $FS::CurrentUser::CurrentUser->access_right('Redownload resolved batches') + ) ) { $html_init .= qq!
!; if ( $fixed ) { -- cgit v1.2.1 From b9ec1f7c51efb5122b7dc88ccadb34e9e99a3b6f Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 3 May 2009 22:45:40 +0000 Subject: break down search.html into components, RT#5108 --- httemplate/search/elements/search-csv.html | 48 +++ httemplate/search/elements/search-html.html | 453 ++++++++++++++++++++++ httemplate/search/elements/search-xls.html | 81 ++++ httemplate/search/elements/search.html | 569 +--------------------------- 4 files changed, 597 insertions(+), 554 deletions(-) create mode 100644 httemplate/search/elements/search-csv.html create mode 100644 httemplate/search/elements/search-html.html create mode 100644 httemplate/search/elements/search-xls.html diff --git a/httemplate/search/elements/search-csv.html b/httemplate/search/elements/search-csv.html new file mode 100644 index 000000000..cd4ea63f5 --- /dev/null +++ b/httemplate/search/elements/search-csv.html @@ -0,0 +1,48 @@ +% $csv->combine(@$header); #or die $csv->status; +% +<% $csv->string %>\ +% +% foreach my $row ( @$rows ) { +% +% if ( $opt{'fields'} ) { +% +% my @line = (); +% +% foreach my $field ( @{$opt{'fields'}} ) { +% if ( ref($field) eq 'CODE' ) { +% push @line, map { +% ref($_) eq 'ARRAY' +% ? '(N/A)' #unimplemented +% : $_; +% } +% &{$field}($row); +% } else { +% push @line, $row->$field(); +% } +% } +% +% $csv->combine(@line); #or die $csv->status; +% +% } else { +% $csv->combine(@$row); #or die $csv->status; +% } +% +% +<% $csv->string %>\ +% +% } +<%init> + +my %args = @_; +my $header = $args{'header'}; +my $rows = $args{'rows'}; +my %opt = %{ $args{'opt'} }; + +#http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes +http_header('Content-Type' => 'text/plain' ); + +my $csv = new Text::CSV_XS { 'always_quote' => 1, + 'eol' => "\n", #"\015\012", #"\012" + }; + + diff --git a/httemplate/search/elements/search-html.html b/httemplate/search/elements/search-html.html new file mode 100644 index 000000000..60dd65a5c --- /dev/null +++ b/httemplate/search/elements/search-html.html @@ -0,0 +1,453 @@ +% +% if ( exists($opt{'redirect'}) && scalar(@$rows) == 1 && $total == 1 +% && $type ne 'html-print' +% ) { +% my $redirect = $opt{'redirect'}; +% $redirect = &{$redirect}($rows->[0], $cgi) if ref($redirect) eq 'CODE'; +% my( $url, $method ) = @$redirect; +% redirect( $url. $rows->[0]->$method() ); +% } elsif ( exists($opt{'redirect_empty'}) && ! scalar(@$rows) && $total == 0 +% && $type ne 'html-print' +% && $opt{'redirect_empty'} +% && ( ref($opt{'redirect_empty'}) ne 'CODE' +% || &{$opt{'redirect_empty'}}($cgi) ) +% ) { +% my $redirect = $opt{'redirect_empty'}; +% $redirect = &{$redirect}($cgi) if ref($redirect) eq 'CODE'; +% redirect( $redirect ); +% } else { +% if ( $opt{'name_singular'} ) { +% $opt{'name'} = PL($opt{'name_singular'}); +% } +% ( my $xlsname = $opt{'name'} ) =~ s/\W//g; +% if ( $total == 1 ) { +% if ( $opt{'name_singular'} ) { +% $opt{'name'} = $opt{'name_singular'} +% } else { +% #$opt{'name'} =~ s/s$// if $total == 1; +% $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1; +% } +% } +% +% if ( $type eq 'html-print' ) { + + <% include( '/elements/header-popup.html', $opt{'title'} ) %> + +% } elsif ( $type eq 'select' ) { + + <% include( '/elements/header-popup.html', $opt{'title'} ) %> + <% defined($opt{'html_init'}) + ? ( ref($opt{'html_init'}) + ? &{$opt{'html_init'}}() + : $opt{'html_init'} + ) + : '' + %> + +% } else { +% +% my @menubar = (); +% if ( $opt{'menubar'} ) { +% @menubar = @{ $opt{'menubar'} }; +% #} else { +% # @menubar = ( 'Main menu' => $p ); +% } + + <% include( '/elements/header.html', $opt{'title'}, + include( '/elements/menubar.html', @menubar ) + ) + %> + + <% defined($opt{'html_init'}) + ? ( ref($opt{'html_init'}) + ? &{$opt{'html_init'}}() + : $opt{'html_init'} + ) + : '' + %> + +% } + +% unless ( $total ) { +% unless ( $opt{'disable_nonefound'} ) { + No matching <% $opt{'name'} %> found.
+% } +% } +% +% if ( $total || $opt{'disableable'} ) { #hmm... and there *are* ones to show?? + + + + + + +% unless ( $opt{'disable_download'} || $type eq 'html-print' ) { + + +% $cgi->param('_type', "html" ); +% } + + + + +% my $h2 = 0; +% foreach my $header ( @{ $opt{header} } ) { +% my $label = ref($header) ? $header->{label} : $header; +% my $rowspan = 1; +% my $style = ''; +% if ( $opt{header2} ) { +% if ( !length($opt{header2}->[$h2]) ) { +% $rowspan = 2; +% splice @{ $opt{header2} }, $h2, 1; +% } else { +% $h2++; +% $style = 'STYLE="border-bottom: none"' +% } +% } + +% } + + +% if ( $opt{header2} ) { + +% foreach my $header ( @{ $opt{header2} } ) { +% my $label = ref($header) ? $header->{label} : $header; + +% } + +% } + +% my $bgcolor1 = '#eeeeee'; +% my $bgcolor2 = '#ffffff'; +% my $bgcolor; +% +% foreach my $row ( @$rows ) { +% +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; +% } + + + +% if ( $opt{'fields'} ) { +% +% my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : ''; +% my $onclicks = $opt{'link_onclicks'} ? [ @{$opt{'link_onclicks'}} ] : []; +% my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : ''; +% my $colors = $opt{'color'} ? [ @{$opt{'color'}} ] : []; +% my $sizes = $opt{'size'} ? [ @{$opt{'size'}} ] : []; +% my $styles = $opt{'style'} ? [ @{$opt{'style'}} ] : []; +% my $cstyles = $opt{'cell_style'} ? [ @{$opt{'cell_style'}} ] : []; +% +% foreach my $field ( +% +% map { +% if ( ref($_) eq 'ARRAY' ) { +% +% my $tableref = $_; +% +% '
+ + + +% if (! $opt{'disable_total'}) { + <% $total %> total <% $opt{'name'} %> +% } + +% if ( $confmax && $total > $confmax +% && ! $opt{'disable_maxselect'} +% && $type ne 'html-print' ) +% { +% $cgi->delete('maxrecords'); +% $cgi->param('_dummy', 1); + + ( show per page ) + +% $cgi->param('maxrecords', $maxrecords); +% } + +% if ( defined($opt{'html_posttotal'}) && $type ne 'html-print' ) { + <% ref($opt{'html_posttotal'}) + ? &{$opt{'html_posttotal'}}() + : $opt{'html_posttotal'} + %> +% } +
+ +% if ( $opt{'count_addl'} ) { +% my $n=0; +% foreach my $count ( @{$opt{'count_addl'}} ) { +% my $data = $count_arrayref->[++$n]; +% if ( ref($count) ) { + <% &{ $count }( $data ) %> +% } else { + <% sprintf( $count, $data ) %>
+% } +% } +% } + + +
+ + Download full results
+ +% $cgi->param('_type', "$xlsname.xls" ); + as Excel spreadsheet
+ +% $cgi->param('_type', 'csv'); + as CSV file
+ +% $cgi->param('_type', 'html-print'); + as printable copy + + <% $opt{'extra_choices_callback'} + ? &{$opt{'extra_choices_callback'}}($cgi->query_string) + : '' + %> + +
+ +% my $pager = ''; +% unless ( $type eq 'html_print' ) { + + <% $pager = include( '/elements/pager.html', + 'offset' => $offset, + 'num_rows' => scalar(@$rows), + 'total' => $total, + 'maxrecords' => $maxrecords, + ) + %> + + <% defined($opt{'html_form'}) + ? ( ref($opt{'html_form'}) + ? &{$opt{'html_form'}}() + : $opt{'html_form'} + ) + : '' + %> + +% } + + <% include('/elements/table-grid.html') %> + +
+ + > + <% $label %> +
+ <% $label %> +
'. +% +% join('', map { +% +% my $rowref = $_; +% +% ''. +% +% join('', map { +% +% my $e = $_; +% +% ''; +% +% } @$rowref ). +% +% ''; +% } @$tableref ). +% +% '
{$_}), +% qw( align bgcolor colspan rowspan +% style valign width ) +% ). +% '>'. +% +% ( $e->{'link'} +% ? '' +% : '' +% ). +% ( $e->{'size'} +% ? '' +% : '' +% ). +% ( $e->{'data_style'} +% ? '<'. uc($e->{'data_style'}). '>' +% : '' +% ). +% $e->{'data'}. +% ( $e->{'data_style'} +% ? '{'data_style'}). '>' +% : '' +% ). +% ( $e->{'size'} ? '' : '' ). +% ( $e->{'link'} ? '' : '' ). +% '
'; +% +% } else { +% $_; +% } +% } +% +% map { +% if ( ref($_) eq 'CODE' ) { +% &{$_}($row); +% } else { +% $row->$_(); +% } +% } +% @{$opt{'fields'}} +% +% ) { +% +% my $class = ( $field =~ /^agentnum ) +% || grep { $row->agentnum == $_ } +% @link_agentnums +% ) { +% +% $link = &{$link}($row) +% if ref($link) eq 'CODE'; +% +% $onclick = &{$onclick}($row) +% if ref($onclick) eq 'CODE'; +% $onclick = qq( onClick="$onclick") if $onclick; +% +% if ( $link ) { +% my( $url, $method ) = @{$link}; +% if ( ref($method) eq 'CODE' ) { +% $a = $url. &{$method}($row); +% } else { +% $a = $url. $row->$method(); +% } +% $a = qq(); +% } +% +% } +% +% } +% +% my $font = ''; +% my $color = shift @$colors; +% $color = &{$color}($row) if ref($color) eq 'CODE'; +% my $size = shift @$sizes; +% $size = &{$size}($row) if ref($size) eq 'CODE'; +% if ( $color || $size ) { +% $font = ''; +% } +% +% my($s, $es) = ( '', '' ); +% my $style = shift @$styles; +% $style = &{$style}($row) if ref($style) eq 'CODE'; +% if ( $style ) { +% $s = join( '', map "<$_>", split('', $style) ); +% $es = join( '', map "", split('', $style) ); +% } +% +% my $cstyle = shift @$cstyles; +% $cstyle = &{$cstyle}($row) if ref($cstyle) eq 'CODE'; +% $cstyle = qq(STYLE="$cstyle") +% if $cstyle; + + + +% } +% +% } else { +% +% foreach ( @$row ) { + +% } +% +% } + + + +% } + +% if ( $opt{'footer'} ) { + + + +% foreach my $footer ( @{ $opt{'footer'} } ) { + +% } + + +% } + +
<% $cstyle %>><% $font %><% $a %><% $s %><% $field %><% $es %><% $a ? '' : '' %><% $font ? '' : '' %><% $_ %>
<% $footer %>
+ + <% $pager %> + + + + +% } + +% if ( $type eq 'html-print' ) { + + + +% } else { + + <% defined($opt{'html_foot'}) + ? ( ref($opt{'html_foot'}) + ? &{$opt{'html_foot'}}() + : $opt{'html_foot'} + ) + : '' + %> + + <% include( '/elements/footer.html' ) %> + +% } + +% } +<%init> + +my %args = @_; +my $type = $args{'type'}; +my $header = $args{'header'}; +my $rows = $args{'rows'}; +my @link_agentnums = @{ $args{'link_agentnums'} }; +my $null_link = $args{'null_link'}; +my $confmax = $args{'confmax'}; +my $maxrecords = $args{'maxrecords'}; +my $offset = $args{'offset'}; +my %opt = %{ $args{'opt'} }; + +my $count_sth = dbh->prepare($opt{'count_query'}) + or die "Error preparing $opt{'count_query'}: ". dbh->errstr; +$count_sth->execute + or die "Error executing $opt{'count_query'}: ". $count_sth->errstr; +my $count_arrayref = $count_sth->fetchrow_arrayref; +my $total = $count_arrayref->[0]; + + diff --git a/httemplate/search/elements/search-xls.html b/httemplate/search/elements/search-xls.html new file mode 100644 index 000000000..8a6ad5cac --- /dev/null +++ b/httemplate/search/elements/search-xls.html @@ -0,0 +1,81 @@ +<% $data %> +<%init> + +my %args = @_; +my $type = $args{'type'}; +my $header = $args{'header'}; +my $rows = $args{'rows'}; +my %opt = %{ $args{'opt'} }; + +#http_header('Content-Type' => 'application/excel' ); #eww +#http_header('Content-Type' => 'application/msexcel' ); #alas +#http_header('Content-Type' => 'application/x-msexcel' ); #? + +#http://support.microsoft.com/kb/199841 +http_header('Content-Type' => 'application/vnd.ms-excel' ); + +#http://support.microsoft.com/kb/812935 +#http://support.microsoft.com/kb/323308 +$HTML::Mason::Commands::r->headers_out->{'Cache-control'} = 'max-age=0'; + +my $data = ''; +my $XLS = new IO::Scalar \$data; +my $workbook = Spreadsheet::WriteExcel->new($XLS) + or die "Error opening .xls file: $!"; + +my $worksheet = $workbook->add_worksheet(substr($opt{'title'},0,31)); + +my($r,$c) = (0,0); + +$worksheet->write($r, $c++, $_) foreach @$header; + +foreach my $row ( @$rows ) { + $r++; + $c = 0; + + if ( $opt{'fields'} ) { + + #my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : ''; + #my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : ''; + + foreach my $field ( @{$opt{'fields'}} ) { + #my $align = $aligns ? shift @$aligns : ''; + #$align = " ALIGN=$align" if $align; + #my $a = ''; + #if ( $links ) { + # my $link = shift @$links; + # $link = &{$link}($row) if ref($link) eq 'CODE'; + # if ( $link ) { + # my( $url, $method ) = @{$link}; + # if ( ref($method) eq 'CODE' ) { + # $a = $url. &{$method}($row); + # } else { + # $a = $url. $row->$method(); + # } + # $a = qq(); + # } + #} + if ( ref($field) eq 'CODE' ) { + foreach my $value ( &{$field}($row) ) { + if ( ref($value) eq 'ARRAY' ) { + $worksheet->write($r, $c++, '(N/A)' ); #unimplemented + } else { + $worksheet->write($r, $c++, $value ); + } + } + } else { + $worksheet->write($r, $c++, $row->$field() ); + } + } + + } else { + $worksheet->write($r, $c++, $_) foreach @$row; + } + +} + +$workbook->close();# or die "Error creating .xls file: $!"; + +http_header('Content-Length' => length($data) ); + + diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html index 8835f8cae..59139327f 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -159,559 +159,27 @@ Example: % if ( $type eq 'csv' ) { % -% #http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes -% http_header('Content-Type' => 'text/plain' ); -% -% my $csv = new Text::CSV_XS { 'always_quote' => 1, -% 'eol' => "\n", #"\015\012", #"\012" -% }; -% -% $csv->combine(@$header); #or die $csv->status; -% -<% $csv->string %> -% -% -% foreach my $row ( @$rows ) { -% -% if ( $opt{'fields'} ) { -% -% my @line = (); -% -% foreach my $field ( @{$opt{'fields'}} ) { -% if ( ref($field) eq 'CODE' ) { -% push @line, map { -% ref($_) eq 'ARRAY' -% ? '(N/A)' #unimplemented -% : $_; -% } -% &{$field}($row); -% } else { -% push @line, $row->$field(); -% } -% } -% -% $csv->combine(@line); #or die $csv->status; -% -% } else { -% $csv->combine(@$row); #or die $csv->status; -% } -% -% -<% $csv->string %> -% -% -% } +<% include('search-csv.html', header=>$header, rows=>$rows, opt=>\%opt ) %> % % #} elsif ( $type eq 'excel' ) { % } elsif ( $type =~ /\.xls$/ ) { % -% #http_header('Content-Type' => 'application/excel' ); #eww -% #http_header('Content-Type' => 'application/msexcel' ); #alas -% #http_header('Content-Type' => 'application/x-msexcel' ); #? -% -% #http://support.microsoft.com/kb/199841 -% http_header('Content-Type' => 'application/vnd.ms-excel' ); -% -% #http://support.microsoft.com/kb/812935 -% #http://support.microsoft.com/kb/323308 -% $HTML::Mason::Commands::r->headers_out->{'Cache-control'} = 'max-age=0'; -% -% my $data = ''; -% my $XLS = new IO::Scalar \$data; -% my $workbook = Spreadsheet::WriteExcel->new($XLS) -% or die "Error opening .xls file: $!"; -% -% my $worksheet = $workbook->add_worksheet(substr($opt{'title'},0,31)); -% -% my($r,$c) = (0,0); -% -% $worksheet->write($r, $c++, $_) foreach @$header; -% -% foreach my $row ( @$rows ) { -% $r++; -% $c = 0; -% -% if ( $opt{'fields'} ) { -% -% #my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : ''; -% #my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : ''; -% -% foreach my $field ( @{$opt{'fields'}} ) { -% #my $align = $aligns ? shift @$aligns : ''; -% #$align = " ALIGN=$align" if $align; -% #my $a = ''; -% #if ( $links ) { -% # my $link = shift @$links; -% # $link = &{$link}($row) if ref($link) eq 'CODE'; -% # if ( $link ) { -% # my( $url, $method ) = @{$link}; -% # if ( ref($method) eq 'CODE' ) { -% # $a = $url. &{$method}($row); -% # } else { -% # $a = $url. $row->$method(); -% # } -% # $a = qq(); -% # } -% #} -% if ( ref($field) eq 'CODE' ) { -% foreach my $value ( &{$field}($row) ) { -% if ( ref($value) eq 'ARRAY' ) { -% $worksheet->write($r, $c++, '(N/A)' ); #unimplemented -% } else { -% $worksheet->write($r, $c++, $value ); -% } -% } -% } else { -% $worksheet->write($r, $c++, $row->$field() ); -% } -% } -% -% } else { -% $worksheet->write($r, $c++, $_) foreach @$row; -% } -% -% } -% -% $workbook->close();# or die "Error creating .xls file: $!"; -% -% http_header('Content-Length' => length($data) ); -% -<% $data %> -% +<% include('search-xls.html', header=>$header, rows=>$rows, opt=>\%opt ) %> % % } else { # regular HTML % -% if ( exists($opt{'redirect'}) && scalar(@$rows) == 1 && $total == 1 -% && $type ne 'html-print' -% ) { -% my $redirect = $opt{'redirect'}; -% $redirect = &{$redirect}($rows->[0], $cgi) if ref($redirect) eq 'CODE'; -% my( $url, $method ) = @$redirect; -% redirect( $url. $rows->[0]->$method() ); -% } elsif ( exists($opt{'redirect_empty'}) && ! scalar(@$rows) && $total == 0 -% && $type ne 'html-print' -% && $opt{'redirect_empty'} -% && ( ref($opt{'redirect_empty'}) ne 'CODE' -% || &{$opt{'redirect_empty'}}($cgi) ) -% ) { -% my $redirect = $opt{'redirect_empty'}; -% $redirect = &{$redirect}($cgi) if ref($redirect) eq 'CODE'; -% redirect( $redirect ); -% } else { -% if ( $opt{'name_singular'} ) { -% $opt{'name'} = PL($opt{'name_singular'}); -% } -% ( my $xlsname = $opt{'name'} ) =~ s/\W//g; -% if ( $total == 1 ) { -% if ( $opt{'name_singular'} ) { -% $opt{'name'} = $opt{'name_singular'} -% } else { -% #$opt{'name'} =~ s/s$// if $total == 1; -% $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1; -% } -% } -% -% if ( $type eq 'html-print' ) { - - <% include( '/elements/header-popup.html', $opt{'title'} ) %> - -% } elsif ( $type eq 'select' ) { - - <% include( '/elements/header-popup.html', $opt{'title'} ) %> - <% defined($opt{'html_init'}) - ? ( ref($opt{'html_init'}) - ? &{$opt{'html_init'}}() - : $opt{'html_init'} - ) - : '' - %> - -% } else { -% -% my @menubar = (); -% if ( $opt{'menubar'} ) { -% @menubar = @{ $opt{'menubar'} }; -% #} else { -% # @menubar = ( 'Main menu' => $p ); -% } - - <% include( '/elements/header.html', $opt{'title'}, - include( '/elements/menubar.html', @menubar ) - ) - %> - - <% defined($opt{'html_init'}) - ? ( ref($opt{'html_init'}) - ? &{$opt{'html_init'}}() - : $opt{'html_init'} - ) - : '' - %> - -% } - -% unless ( $total ) { -% unless ( $opt{'disable_nonefound'} ) { - No matching <% $opt{'name'} %> found.
-% } -% } -% -% if ( $total || $opt{'disableable'} ) { #hmm... and there *are* ones to show?? - - - - - - -% unless ( $opt{'disable_download'} || $type eq 'html-print' ) { - - -% $cgi->param('_type', "html" ); -% } - - - - -% my $h2 = 0; -% foreach my $header ( @{ $opt{header} } ) { -% my $label = ref($header) ? $header->{label} : $header; -% my $rowspan = 1; -% my $style = ''; -% if ( $opt{header2} ) { -% if ( !length($opt{header2}->[$h2]) ) { -% $rowspan = 2; -% splice @{ $opt{header2} }, $h2, 1; -% } else { -% $h2++; -% $style = 'STYLE="border-bottom: none"' -% } -% } - -% } - - -% if ( $opt{header2} ) { - -% foreach my $header ( @{ $opt{header2} } ) { -% my $label = ref($header) ? $header->{label} : $header; - -% } - -% } - -% my $bgcolor1 = '#eeeeee'; -% my $bgcolor2 = '#ffffff'; -% my $bgcolor; -% -% foreach my $row ( @$rows ) { -% -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } - - - -% if ( $opt{'fields'} ) { -% -% my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : ''; -% my $onclicks = $opt{'link_onclicks'} ? [ @{$opt{'link_onclicks'}} ] : []; -% my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : ''; -% my $colors = $opt{'color'} ? [ @{$opt{'color'}} ] : []; -% my $sizes = $opt{'size'} ? [ @{$opt{'size'}} ] : []; -% my $styles = $opt{'style'} ? [ @{$opt{'style'}} ] : []; -% my $cstyles = $opt{'cell_style'} ? [ @{$opt{'cell_style'}} ] : []; -% -% foreach my $field ( -% -% map { -% if ( ref($_) eq 'ARRAY' ) { -% -% my $tableref = $_; -% -% '
- -
- -% if (! $opt{'disable_total'}) { - <% $total %> total <% $opt{'name'} %> -% } - -% if ( $confmax && $total > $confmax -% && ! $opt{'disable_maxselect'} -% && $type ne 'html-print' ) -% { -% $cgi->delete('maxrecords'); -% $cgi->param('_dummy', 1); - - ( show per page ) - -% $cgi->param('maxrecords', $maxrecords); -% } - -% if ( defined($opt{'html_posttotal'}) && $type ne 'html-print' ) { - <% ref($opt{'html_posttotal'}) - ? &{$opt{'html_posttotal'}}() - : $opt{'html_posttotal'} - %> -% } -
- -% if ( $opt{'count_addl'} ) { -% my $n=0; -% foreach my $count ( @{$opt{'count_addl'}} ) { -% my $data = $count_arrayref->[++$n]; -% if ( ref($count) ) { - <% &{ $count }( $data ) %> -% } else { - <% sprintf( $count, $data ) %>
-% } -% } -% } -
- -
- - Download full results
- -% $cgi->param('_type', "$xlsname.xls" ); - as Excel spreadsheet
- -% $cgi->param('_type', 'csv'); - as CSV file
- -% $cgi->param('_type', 'html-print'); - as printable copy - - <% $opt{'extra_choices_callback'} - ? &{$opt{'extra_choices_callback'}}($cgi->query_string) - : '' - %> - -
- -% my $pager = ''; -% unless ( $type eq 'html_print' ) { - - <% $pager = include( '/elements/pager.html', - 'offset' => $offset, - 'num_rows' => scalar(@$rows), - 'total' => $total, - 'maxrecords' => $maxrecords, - ) - %> - - <% defined($opt{'html_form'}) - ? ( ref($opt{'html_form'}) - ? &{$opt{'html_form'}}() - : $opt{'html_form'} - ) - : '' - %> - -% } - - <% include('/elements/table-grid.html') %> - -
- - > - <% $label %> -
- <% $label %> -
'. -% -% join('', map { -% -% my $rowref = $_; -% -% ''. -% -% join('', map { -% -% my $e = $_; -% -% ''; -% -% } @$rowref ). -% -% ''; -% } @$tableref ). -% -% '
{$_}), -% qw( align bgcolor colspan rowspan -% style valign width ) -% ). -% '>'. -% -% ( $e->{'link'} -% ? '' -% : '' -% ). -% ( $e->{'size'} -% ? '' -% : '' -% ). -% ( $e->{'data_style'} -% ? '<'. uc($e->{'data_style'}). '>' -% : '' -% ). -% $e->{'data'}. -% ( $e->{'data_style'} -% ? '{'data_style'}). '>' -% : '' -% ). -% ( $e->{'size'} ? '' : '' ). -% ( $e->{'link'} ? '' : '' ). -% '
'; -% -% } else { -% $_; -% } -% } -% -% map { -% if ( ref($_) eq 'CODE' ) { -% &{$_}($row); -% } else { -% $row->$_(); -% } -% } -% @{$opt{'fields'}} -% -% ) { -% -% my $class = ( $field =~ /^agentnum ) -% || grep { $row->agentnum == $_ } -% @link_agentnums -% ) { -% -% $link = &{$link}($row) -% if ref($link) eq 'CODE'; -% -% $onclick = &{$onclick}($row) -% if ref($onclick) eq 'CODE'; -% $onclick = qq( onClick="$onclick") if $onclick; -% -% if ( $link ) { -% my( $url, $method ) = @{$link}; -% if ( ref($method) eq 'CODE' ) { -% $a = $url. &{$method}($row); -% } else { -% $a = $url. $row->$method(); -% } -% $a = qq(); -% } -% -% } -% -% } -% -% my $font = ''; -% my $color = shift @$colors; -% $color = &{$color}($row) if ref($color) eq 'CODE'; -% my $size = shift @$sizes; -% $size = &{$size}($row) if ref($size) eq 'CODE'; -% if ( $color || $size ) { -% $font = ''; -% } -% -% my($s, $es) = ( '', '' ); -% my $style = shift @$styles; -% $style = &{$style}($row) if ref($style) eq 'CODE'; -% if ( $style ) { -% $s = join( '', map "<$_>", split('', $style) ); -% $es = join( '', map "", split('', $style) ); -% } -% -% my $cstyle = shift @$cstyles; -% $cstyle = &{$cstyle}($row) if ref($cstyle) eq 'CODE'; -% $cstyle = qq(STYLE="$cstyle") -% if $cstyle; - - - -% } -% -% } else { -% -% foreach ( @$row ) { - -% } -% -% } - - - -% } - -% if ( $opt{'footer'} ) { - - - -% foreach my $footer ( @{ $opt{'footer'} } ) { - -% } - - -% } - -
<% $cstyle %>><% $font %><% $a %><% $s %><% $field %><% $es %><% $a ? '' : '' %><% $font ? '' : '' %><% $_ %>
<% $footer %>
- - <% $pager %> - - - - -% } - -% if ( $type eq 'html-print' ) { - - - -% } else { - - <% defined($opt{'html_foot'}) - ? ( ref($opt{'html_foot'}) - ? &{$opt{'html_foot'}}() - : $opt{'html_foot'} - ) - : '' - %> - - <% include( '/elements/footer.html' ) %> - -% } - -% } +<% include('search-html.html', + type => $type, + header => $header, + rows => $rows, + link_agentnums => \@link_agentnums, + null_link => $null_link, + confmax => $confmax, + maxrecords => $maxrecords, + offset => $offset, + opt => \%opt + ) +%> % % } <%init> @@ -833,7 +301,7 @@ my $type = $cgi->param('_type') =~ /^(csv|\w*\.xls|select|html(-print)?)$/ ? $1 : 'html'; my $limit = ''; -my($confmax, $maxrecords, $total, $offset, $count_arrayref); +my($confmax, $maxrecords, $offset ); unless ( $type =~ /^(csv|\w*\.xls)$/ ) { @@ -867,13 +335,6 @@ unless ( $type =~ /^(csv|\w*\.xls)$/ ) { } - my $count_sth = dbh->prepare($opt{'count_query'}) - or die "Error preparing $opt{'count_query'}: ". dbh->errstr; - $count_sth->execute - or die "Error executing $opt{'count_query'}: ". $count_sth->errstr; - $count_arrayref = $count_sth->fetchrow_arrayref; - $total = $count_arrayref->[0]; - } # run the query -- cgit v1.2.1 From 9f73c5d4c0954b3a03bfcb5e010fc288a7071209 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 4 May 2009 00:22:44 +0000 Subject: add menu item and page for d/ling and edit rates with excel. RT#5108 --- httemplate/browse/rate_region.html | 13 +++++--- httemplate/elements/menu.html | 16 ++++++---- httemplate/misc/rate_edit_excel.html | 51 ++++++++++++++++++++++++++++++ httemplate/search/elements/search-xls.html | 42 ++++++++++++------------ httemplate/search/elements/search.html | 8 +++-- 5 files changed, 97 insertions(+), 33 deletions(-) create mode 100644 httemplate/misc/rate_edit_excel.html diff --git a/httemplate/browse/rate_region.html b/httemplate/browse/rate_region.html index 456ba3452..4e4986987 100644 --- a/httemplate/browse/rate_region.html +++ b/httemplate/browse/rate_region.html @@ -15,6 +15,7 @@ 'header' => \@header, 'fields' => \@fields, 'links' => \@links, + 'xls_format' => \@xls_format, ) %> <%once> @@ -40,7 +41,7 @@ if ( driver_name =~ /^Pg/ ) { " END"; my $prefixes_sql = "SELECT $prefix_sql $fromwhere AND npa IS NOT NULL"; $select .= "( SELECT countrycode $fromwhere LIMIT 1 ) AS ccode, - ARRAY_TO_STRING( ARRAY($prefixes_sql), ', ' ) AS prefixes"; + ARRAY_TO_STRING( ARRAY($prefixes_sql), ',' ) AS prefixes"; } elsif ( driver_name =~ /^mysql/i ) { $join = 'LEFT JOIN rate_prefix USING ( regionnum )'; $select .= "GROUP_CONCAT( DISTINCT countrycode ) AS ccode, @@ -60,9 +61,10 @@ tie my %granularity, 'Tie::IxHash', FS::rate_detail::granularities(); die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my @header = ( '#', 'Region', 'Country code', 'Prefixes' ); -my @fields = ( 'regionnum', 'regionname', 'ccode', 'prefixes' ); -my @links = ( $link, $link, $link, $link ); +my @header = ( '#', 'Region', 'Country code', 'Prefixes' ); +my @fields = ( 'regionnum', 'regionname', 'ccode', 'prefixes' ); +my @links = ( ($link) x 4 ); +my @xls_format = ( ({ locked=>1, bg_color=>22 }) x 4 ); $cgi->param('dummy', 1); my $countrycode_filter_change = @@ -110,7 +112,8 @@ if ( $cgi->param('show_rates') ) { _rate_detail_factory($rate, 'sec_granularity'), _rate_detail_factory($rate, 'classnum'); - push @links, '', '', '', ''; + push @links, ( ('') x 4 ); + push @xls_format, ( ({}) x 4 ); } diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 409a1525a..487373710 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -227,13 +227,16 @@ tie my %tools_importing, 'Tie::IxHash', 'Import payments from CSV file' => [ $fsurl.'misc/cust_pay-import.cgi', '' ], 'Import phone numbers (DIDs)' => [ $fsurl.'misc/phone_avail-import.html', '' ], 'Import Call Detail Records (CDRs) from CSV file' => [ $fsurl.'misc/cdr-import.html', '' ], +# 'Import call rates and regions' => [ $fsurl.'misc/rate-import.html', '' ], ; -if ( $conf->exists('taxdatadirectdownload') ) { - $tools_importing{'Import tax rates from vendor site'} = - [ $fsurl.'misc/tax-fetch_and_import.cgi', '' ]; -} else { - $tools_importing{'Import tax rates from CSV files'} = - [ $fsurl.'misc/tax-import.cgi', '' ]; +if ( $conf->exists('enable_taxproducts') ) { + if ( $conf->exists('taxdatadirectdownload') ) { + $tools_importing{'Import tax rates from vendor site'} = + [ $fsurl.'misc/tax-fetch_and_import.cgi', '' ]; + } else { + $tools_importing{'Import tax rates from CSV files'} = + [ $fsurl.'misc/tax-import.cgi', '' ]; + } } tie my %tools_exporting, 'Tie::IxHash', @@ -292,6 +295,7 @@ tie my %config_billing_rates, 'Tie::IxHash', 'View/Edit rate plans' => [ $fsurl.'browse/rate.cgi', 'Manage rate plans' ], 'View/Edit regions and prefixes' => [ $fsurl.'browse/rate_region.html', 'Manage regions and prefixes' ], 'View/Edit usage classes' => [ $fsurl.'browse/usage_class.html', 'Usage classes define groups of usage for taxation purposes.' ], + 'Edit rates with Excel' => [ $fsurl.'misc/rate_edit_excel.html', 'Download and edit rates with Excel, then upload changes.' ], ; tie my %config_billing, 'Tie::IxHash'; diff --git a/httemplate/misc/rate_edit_excel.html b/httemplate/misc/rate_edit_excel.html new file mode 100644 index 000000000..7d3255301 --- /dev/null +++ b/httemplate/misc/rate_edit_excel.html @@ -0,0 +1,51 @@ +<% include('/elements/header.html', 'Edit rates with Excel' ) %> + +<% include( '/elements/form-file_upload.html', + 'name' => 'RateImportForm', + 'action' => 'process/rate_edit_excel.html', + 'num_files' => 1, + 'fields' => [ 'format' ], #? + 'message' => 'Rate edit successful', + 'url' => $p."browse/rate_region.html", + ) +%> + +<% &ntable("#cccccc", 2) %> + + + 1. Download current rates: + + Download rate spreadsheet + + + + + 2. Edit rates with Excel (or other .XLS-compatible application) + + + <% include( '/elements/file-upload.html', + 'field' => 'file', + 'label' => '3. Upload edited rate file: '. ( ' 'x4 ), #yuck + ) + %> + + + + + + + + + + +<% include('/elements/footer.html') %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + + diff --git a/httemplate/search/elements/search-xls.html b/httemplate/search/elements/search-xls.html index 8a6ad5cac..8a05e477c 100644 --- a/httemplate/search/elements/search-xls.html +++ b/httemplate/search/elements/search-xls.html @@ -25,9 +25,18 @@ my $workbook = Spreadsheet::WriteExcel->new($XLS) my $worksheet = $workbook->add_worksheet(substr($opt{'title'},0,31)); +$worksheet->protect(); + my($r,$c) = (0,0); -$worksheet->write($r, $c++, $_) foreach @$header; +my $header_format = $workbook->add_format( + bold => 1, + locked => 1, + bg_color => 55, #22, + bottom => 3, +); + +$worksheet->write($r, $c++, $_, $header_format ) foreach @$header; foreach my $row ( @$rows ) { $r++; @@ -37,39 +46,32 @@ foreach my $row ( @$rows ) { #my $links = $opt{'links'} ? [ @{$opt{'links'}} ] : ''; #my $aligns = $opt{'align'} ? [ @{$opt{'align'}} ] : ''; + #could also translate color, size, style into xls equivalents? + my $formats = $opt{'xls_format'} ? [ @{$opt{'xls_format'}} ] : []; foreach my $field ( @{$opt{'fields'}} ) { - #my $align = $aligns ? shift @$aligns : ''; - #$align = " ALIGN=$align" if $align; - #my $a = ''; - #if ( $links ) { - # my $link = shift @$links; - # $link = &{$link}($row) if ref($link) eq 'CODE'; - # if ( $link ) { - # my( $url, $method ) = @{$link}; - # if ( ref($method) eq 'CODE' ) { - # $a = $url. &{$method}($row); - # } else { - # $a = $url. $row->$method(); - # } - # $a = qq(); - # } - #} + + my $format = shift @$formats; + $format = &{$format}($row) if ref($format) eq 'CODE'; + $format ||= {}; + my $xls_format = $workbook->add_format(locked=>0, %$format); + if ( ref($field) eq 'CODE' ) { foreach my $value ( &{$field}($row) ) { if ( ref($value) eq 'ARRAY' ) { $worksheet->write($r, $c++, '(N/A)' ); #unimplemented } else { - $worksheet->write($r, $c++, $value ); + $worksheet->write($r, $c++, $value, $xls_format ); } } } else { - $worksheet->write($r, $c++, $row->$field() ); + $worksheet->write($r, $c++, $row->$field(), $xls_format ); } } } else { - $worksheet->write($r, $c++, $_) foreach @$row; + my $xls_format = $workbook->add_format(locked=>0); + $worksheet->write($r, $c++, $_, $xls_format ) foreach @$row; } } diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html index 59139327f..a66176d00 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -148,11 +148,15 @@ Example: 'align' => 'lrc.', #listrefs of ( scalars or coderefs ) - #currently only HTML, maybe eventually Excel too + # currently only HTML, maybe eventually Excel too 'color' => [], 'size' => [], 'style' => [], # or , etc. 'cell_style' => [], #STYLE= attribute of TR, very HTML-specific... + + # Excel-specific listref of ( hashrefs or coderefs ) + # each hashref: http://search.cpan.org/dist/Spreadsheet-WriteExcel/lib/Spreadsheet/WriteExcel.pm#Format_methods_and_Format_properties + 'xls_format' => => [], ); @@ -227,7 +231,7 @@ if ( $opt{'agent_virt'} ) { #false laziness w/statuspos above my $pos = $opt{'agent_pos'}; - foreach my $att (qw( align style color size )) { + foreach my $att (qw( align color size style cell_style xls_format )) { $opt{$att} ||= [ map '', @{ $opt{'fields'} } ]; } -- cgit v1.2.1 From e9b930f5813d6df9e13d89c36ca0d7fc7973d2bc Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 4 May 2009 01:17:24 +0000 Subject: eliminate Argument "" isn't numeric in addition (+) warning --- FS/FS/svc_acct.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 9ab90349f..955547b73 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1711,7 +1711,7 @@ my %op2condition = ( $self->$column - $amount <= 0; }, '+' => sub { my($self, $column, $amount) = @_; - $self->$column + $amount > 0; + ($self->$column || 0) + $amount > 0; }, ); my %op2warncondition = ( @@ -1720,7 +1720,7 @@ my %op2warncondition = ( $self->$column - $amount <= $self->$threshold + 0; }, '+' => sub { my($self, $column, $amount) = @_; - $self->$column + $amount > 0; + ($self->$column || 0) + $amount > 0; }, ); -- cgit v1.2.1 From b528a04c4f4ae1addb1cb22e0489f7c5dc5941b8 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 4 May 2009 02:01:43 +0000 Subject: agent-virt prepaid income report, RT#5311 --- httemplate/search/report_prepaid_income.cgi | 38 ++++++++++++--- httemplate/search/report_prepaid_income.html | 70 +++++++++++++++++----------- 2 files changed, 75 insertions(+), 33 deletions(-) diff --git a/httemplate/search/report_prepaid_income.cgi b/httemplate/search/report_prepaid_income.cgi index 27dbcbf9f..ce928b81c 100644 --- a/httemplate/search/report_prepaid_income.cgi +++ b/httemplate/search/report_prepaid_income.cgi @@ -38,22 +38,46 @@ my $now = $cgi->param('date') && str2time($cgi->param('date')) || $time; $now =~ /^(\d+)$/ or die "unparsable date?"; $now = $1; +my @where = (); + +if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + my $agentnum = $1; + push @where, "agentnum = $agentnum"; +} + +#here is the agent virtualization +push @where, $FS::CurrentUser::CurrentUser->agentnums_sql; + +my $where = join(' AND ', @where); +$where = "AND $where" if $where; + my( $total, $total_legacy ) = ( 0, 0 ); my @cust_bill_pkg = grep { $_->cust_pkg && $_->cust_pkg->part_pkg->freq !~ /^([01]|\d+[dw])$/ } - qsearch( 'cust_bill_pkg', { - 'recur' => { op=>'!=', value=>0 }, - 'edate' => { op=>'>', value=>$now }, - }, ); + qsearch({ + 'select' => 'cust_bill_pkg.*', + 'table' => 'cust_bill_pkg', + 'addl_from' => ' LEFT JOIN cust_bill USING ( invnum ) '. + ' LEFT JOIN cust_main USING ( custnum ) ', + 'hashref' => { + 'recur' => { op=>'!=', value=>0 }, + 'edate' => { op=>'>', value=>$now }, + }, + 'extra_sql' => $where, + }); my @cust_pkg = grep { $_->part_pkg->recur != 0 && $_->part_pkg->freq !~ /^([01]|\d+[dw])$/ } - qsearch ( 'cust_pkg', { - 'bill' => { op=>'>', value=>$now } - } ); + qsearch({ + 'select' => 'cust_pkg.*', + 'table' => 'cust_pkg', + 'addl_from' => ' LEFT JOIN cust_main USING ( custnum ) ', + 'hashref' => { 'bill' => { op=>'>', value=>$now } }, + 'extra_sql' => $where, + }); foreach my $cust_bill_pkg ( @cust_bill_pkg) { my $period = $cust_bill_pkg->edate - $cust_bill_pkg->sdate; diff --git a/httemplate/search/report_prepaid_income.html b/httemplate/search/report_prepaid_income.html index 81adb64ad..d707bd81b 100644 --- a/httemplate/search/report_prepaid_income.html +++ b/httemplate/search/report_prepaid_income.html @@ -1,28 +1,46 @@ -<% include('/elements/header.html', 'Prepaid Income (Unearned Revenue) Report', - '', - '', - ' - - - - ' -) %> - -
- - - - - - - - - -
Prepaid income (unearned revenue) as of - - -
- m/d/y
+<% include('/elements/header.html','Prepaid Income (Unearned Revenue) Report')%> + +<% include('/elements/init_calendar.html') %> + + + + + + + + + + + + + + + + + + + + + + + <% include( '/elements/tr-select-agent.html', 'disable_empty'=>0 ) %> + + + + + + + + + +
+ Search options +
As of + + +
+ m/d/y
 
 
+ - +
<% include('/elements/footer.html') %> <%init> -- cgit v1.2.1 From 4c13f5c6bb96b79087bdbc2f3a424dac02e9f998 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 4 May 2009 18:33:48 +0000 Subject: this is a quick hack to rebill customers when a cdr didn't happen --- bin/cust_main_special.pm | 776 +++++++++++++++++++++++++++++++++++++++++++++++ bin/rebill | 132 ++++++++ 2 files changed, 908 insertions(+) create mode 100644 bin/cust_main_special.pm create mode 100755 bin/rebill diff --git a/bin/cust_main_special.pm b/bin/cust_main_special.pm new file mode 100644 index 000000000..1f3203e1d --- /dev/null +++ b/bin/cust_main_special.pm @@ -0,0 +1,776 @@ +package cust_main_special; + +require 5.006; +use strict; +use vars qw( @ISA $DEBUG $me $conf ); +use Safe; +use Carp; +use Data::Dumper; +use Date::Format; +use FS::UID qw( dbh ); +use FS::Record qw( qsearchs qsearch ); +use FS::payby; +use FS::cust_pkg; +use FS::cust_bill; +use FS::cust_bill_pkg; +use FS::cust_bill_pkg_display; +use FS::cust_bill_pkg_tax_location; +use FS::cust_main_county; +use FS::cust_location; +use FS::tax_rate; +use FS::cust_tax_location; +use FS::part_pkg_taxrate; +use FS::queue; +use FS::part_pkg; + +@ISA = qw ( FS::cust_main ); + +$DEBUG = 0; +$me = '[emergency billing program]'; + +$conf = new FS::Conf; + +=head1 METHODS + +=over 4 + +=item bill_and_collect + +Cancels and suspends any packages due, generates bills, applies payments and +cred + +Warns on errors (Does not currently: If there is an error, returns the error, otherwise returns false.) + +Options are passed as name-value pairs. Currently available options are: + +=over 4 + +=item time + +Bills the customer as if it were that time. Specified as a UNIX timestamp; see L). Also see L and L for conversion functions. For example: + + use Date::Parse; + ... + $cust_main->bill( 'time' => str2time('April 20th, 2001') ); + +=item invoice_time + +Used in conjunction with the I
POP number!, @@ -244,15 +244,14 @@ sub table_info { }, '_password' => 'Password', 'gid' => { - label => 'GID', - def_label => 'GID (when blank, defaults to UID)', - type => 'text', + label => 'GID', + def_info => 'when blank, defaults to UID', + type => 'text', }, 'shell' => { - #desc =>'Shell (all service definitions should have a default or fixed shell that is present in the shells configuration file, set to blank for no shell tracking)', label => 'Shell', - def_label=> 'Shell (set to blank for no shell tracking)', - type =>'select', + def_info => 'set to blank for no shell tracking', + type => 'select', #select_list => [ $conf->config('shells') ], select_list => [ $conf ? $conf->config('shells') : () ], disable_inventory => 1, @@ -261,7 +260,6 @@ sub table_info { 'finger' => 'Real name', # (GECOS)', 'domsvc' => { label => 'Domain', - #def_label => 'svcnum from svc_domain', type => 'select', select_table => 'svc_domain', select_key => 'svcnum', diff --git a/httemplate/browse/part_svc.cgi b/httemplate/browse/part_svc.cgi index f1b283638..94afdef15 100755 --- a/httemplate/browse/part_svc.cgi +++ b/httemplate/browse/part_svc.cgi @@ -55,6 +55,8 @@ function part_export_areyousure(href) { Field + Label + Modifier @@ -65,8 +67,15 @@ function part_export_areyousure(href) { % my @dfields = $svc_x->fields; % push @dfields, 'usergroup' if $svcdb eq 'svc_acct'; #kludge % my @fields = -% grep { $svc_x->pvf($_) -% or $_ ne 'svcnum' && $part_svc->part_svc_column($_)->columnflag } +% grep { my $col = $part_svc->part_svc_column($_); +% my $def = FS::part_svc->svc_table_fields($svcdb)->{$_}; +% $svc_x->pvf($_) +% or $_ ne 'svcnum' && ( +% $col->columnflag || ( $col->columnlabel !~ /^\S*$/ +% && $col->columnlabel ne $def->{'label'} +% ) +% ) +% } % @dfields ; % my $rowspan = scalar(@fields) || 1; % my $url = "${p}edit/part_svc.cgi?". $part_svc->svcpart; @@ -128,21 +137,25 @@ function part_export_areyousure(href) { % unless ( @fields ) { -% for ( 1..3 ) { +% for ( 1..4 ) { % } % } % % my($n1)=''; % foreach my $field ( @fields ) { -% my $formatter = -% FS::part_svc->svc_table_fields($svcdb)->{$field}->{format} -% || sub { shift }; -% my $flag = $part_svc->part_svc_column($field)->columnflag; % +% #a few lines of false laziness w/edit/part_svc.cgi +% my $def = FS::part_svc->svc_table_fields($svcdb)->{$field}; +% my $formatter = $def->{format} || sub { shift }; +% +% my $part_svc_column = $part_svc->part_svc_column($field); +% my $label = $part_svc_column->columnlabel || $def->{'label'}; +% my $flag = $part_svc_column->columnflag; <% $n1 %> <% $field %> + <% $label %> <% $flag{$flag} %> diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index deb3c80f9..79703435c 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -122,6 +122,7 @@ that field. % $html .= include('/elements/table-grid.html', 'cellpadding' => 4 ). % ''. % 'Field'. +% 'Label'. % 'Modifier'. % ''; % @@ -146,13 +147,15 @@ that field. % % foreach my $field (@fields) { % -% #my $def = $defs{$layer}{$field}; +% #a few lines of false laziness w/browse/part_svc.cgi % my $def = FS::part_svc->svc_table_fields($layer)->{$field}; -% my $label = $def->{'def_label'} || $def->{'label'}; +% my $def_info = $def->{'def_info'}; % my $formatter = $def->{'format'} || sub { shift }; +% % my $part_svc_column = $part_svc->part_svc_column($field); +% my $label = $part_svc_column->columnlabel || $def->{'label'}; % my $value = &$formatter($part_svc_column->columnvalue); -% my $flag = $part_svc_column->columnflag; +% my $flag = $part_svc_column->columnflag; % % if ( $bgcolor eq $bgcolor1 ) { % $bgcolor = $bgcolor2; @@ -160,9 +163,12 @@ that field. % $bgcolor = $bgcolor1; % } % -% $html .= qq!!. -% ( $label || $field ). +% $html .= qq!!. +% ( $def->{'label'} || $field ). % ""; +% +% $html .= qq!'; +% % $flag = '' if $def->{type} eq 'disabled'; % % $html .= qq!!; @@ -302,6 +308,15 @@ that field. % } % % $html .= "\n"; + +% $def_info = "($def_info)" if $def_info; +% $html .= +% qq!!. +% qq! !. +% qq! $def_info!. +% qq! !. +% qq!\n!; % % } #foreach my $field (@fields) { % -- cgit v1.2.1 From 39120f69d4372781aba0df58d06736be450009e1 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 9 May 2009 01:44:08 +0000 Subject: use service-def specific labels, at least for service pages that use {view,edit}/elements/svc_Common.html RT#4081 --- httemplate/edit/elements/edit.html | 36 +++++++++++++++++--------------- httemplate/edit/elements/svc_Common.html | 28 ++++++++++++++++++++++--- httemplate/view/elements/svc_Common.html | 8 +++++++ 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index d18a37d5a..4a6079a85 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -132,37 +132,39 @@ Example: # initialization callbacks ### - ###global callbacks + ###global callbacks, always run if provided - #always run if provided, after decoding long CGI "redirect=" responses but + #after decoding long CGI "redirect=" responses but # before object creation/search # (useful if you have a long form that might trigger redirect= and you need # to do things with $cgi params - they're not decoded in the calling # <%init> block yet) 'begin_callback' = sub { my( $cgi, $fields_listref, $opt_hashref ) = @_; }, - #always run, after the mode-specific object creation/search + #after the mode-specific object creation/search 'end_callback' = sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, - ###mode-specific callbacks + ###mode-specific callbacks. one (and only one) of these four is called + #run when adding + 'new_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, + + #run when editing + 'edit_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, + #run when re-displaying with an error 'error_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, - #run when editing - 'edit_callback' => sub { my( $cgi, $object, $fields_listref ) = @_; }, - + #run when cloning + 'clone_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, + + ###callbacks called in new mode only + # returns a hashref for the new object 'new_hashref_callback' # returns the new object iself (otherwise, ->new is called) 'new_object_callback' - - #run when adding - 'new_callback' => sub { my( $cgi, $object, $fields_listref ) = @_; }, - - #run when cloning - 'clone_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, ###display callbacks @@ -618,7 +620,7 @@ if ( $cgi->param('error') ) { map { $_ => scalar($cgi->param($_)) } fields($table) }); - &{$opt{'error_callback'}}($cgi, $object, $fields, \%opt ) + &{$opt{'error_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'error_callback'}; } elsif ( $cgi->param('clone') =~ /^(\d+)$/ ) { @@ -632,7 +634,7 @@ if ( $cgi->param('error') ) { $object = qsearchs({ %qsearch, 'hashref' => { $pkey => $clone } }); - &{$opt{'clone_callback'}}($cgi, $object, $fields, \%opt ) + &{$opt{'clone_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'clone_callback'}; #$object->$pkey(''); @@ -657,7 +659,7 @@ if ( $cgi->param('error') ) { warn "$table $pkey => $1" if $opt{'debug'}; - &{$opt{'edit_callback'}}($cgi, $object, $fields) + &{$opt{'edit_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'edit_callback'}; } else { #adding @@ -672,7 +674,7 @@ if ( $cgi->param('error') ) { ? &{$opt{'new_object_callback'}}( $cgi, $hashref, $fields, \%opt ) : $class->new( $hashref ); - &{$opt{'new_callback'}}($cgi, $object, $fields) + &{$opt{'new_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'new_callback'}; } diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html index 0b64120fb..ef04bd04a 100644 --- a/httemplate/edit/elements/svc_Common.html +++ b/httemplate/edit/elements/svc_Common.html @@ -3,7 +3,7 @@ 'menubar' => [], 'error_callback' => sub { - my( $cgi, $svc_x ) = @_; + my( $cgi, $svc_x, $fields, $opt ) = @_; #$svcnum = $svc_x->svcnum; $pkgnum = $cgi->param('pkgnum'); $svcpart = $cgi->param('svcpart'); @@ -11,11 +11,13 @@ $part_svc = qsearchs( 'part_svc', { svcpart=>$svcpart }); die "No part_svc entry!" unless $part_svc; + label_fixup($part_svc, $opt); + $svc_x->setfield('svcpart', $svcpart); }, 'edit_callback' => sub { - my( $cgi, $svc_x ) = @_; + my( $cgi, $svc_x, $fields, $opt ) = @_; #$svcnum = $svc_x->svcnum; my $cust_svc = $svc_x->cust_svc or die "Unknown (cust_svc) svcnum!"; @@ -25,6 +27,8 @@ $part_svc = qsearchs ('part_svc', { svcpart=>$svcpart }); die "No part_svc entry!" unless $part_svc; + + label_fixup($part_svc, $opt); }, 'new_hashref_callback' => sub { @@ -35,11 +39,13 @@ }, 'new_callback' => sub { - my( $cgi, $svc_x ) = @_;; + my( $cgi, $svc_x, $fields, $opt ) = @_;; $part_svc = qsearchs( 'part_svc', { svcpart=>$svcpart }); die "No part_svc entry!" unless $part_svc; + label_fixup($part_svc, $opt); + #$svcnum=''; $svc_x->set_default_and_fixed; @@ -100,6 +106,22 @@ %opt #pass through/override params ) %> +<%once> + +sub label_fixup { + my( $part_svc, $opt ) = @_; + + #false laziness w/view/svc_Common.html + #override default labels with service-definition labels if applicable + my $labels = $opt->{labels}; # with -> here + foreach my $field ( keys %$labels ) { + my $col = $part_svc->part_svc_column($field); + $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\S*$/; + } + +} + + <%init> my %opt = @_; diff --git a/httemplate/view/elements/svc_Common.html b/httemplate/view/elements/svc_Common.html index 125fcd0b8..852640e0c 100644 --- a/httemplate/view/elements/svc_Common.html +++ b/httemplate/view/elements/svc_Common.html @@ -145,6 +145,14 @@ my($label, $value, $svcdb) = $cust_svc->label; my $part_svc = $cust_svc->part_svc; + #false laziness w/edit/svc_Common.html + #override default labels with service-definition labels if applicable + my $labels = $opt{labels}; #not -> here + foreach my $field ( keys %$labels ) { + my $col = $part_svc->part_svc_column($field); + $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\S*$/; + } + my $pkgnum = $cust_svc->pkgnum; my($cust_pkg, $custnum); -- cgit v1.2.1 From a70e4bb88f298f93292380d1e2feb80e1baa13f8 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 9 May 2009 07:56:38 +0000 Subject: add cdr-charged_party-truncate_{length,prefix} in order to trim charged_party to a certain length, RT#4081 --- FS/FS/Conf.pm | 16 +++++++++++++++- FS/FS/cdr.pm | 12 ++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index ebfad2c36..e86ed0d15 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2718,10 +2718,24 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'cdr-charged_party-truncate_prefix', + 'section' => '', + 'description' => 'If the charged_party field has this prefix, truncate it to the length in cdr-charged_party-truncate_length.', + 'type' => 'text', + }, + + { + 'key' => 'cdr-charged_party-truncate_length', + 'section' => '', + 'description' => 'If the charged_party field has the prefix in cdr-charged_party-truncate_prefix, truncate it to this length.', + 'type' => 'text', + }, + { 'key' => 'cdr-charged_party_rewrite', 'section' => '', - 'description' => 'Do charged party rewriting in the freeside-cdrrewrited daemon; useful if CDRs are being dropped off directly in the database and require special charged_party processing such as cdr-charged_party-accountcode.', + 'description' => 'Do charged party rewriting in the freeside-cdrrewrited daemon; useful if CDRs are being dropped off directly in the database and require special charged_party processing such as cdr-charged_party-accountcode or cdr-charged_party-truncate*.', 'type' => 'checkbox', }, diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index b640bc63e..2a235cc41 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -295,9 +295,9 @@ or to the dst field if it is a toll free number. sub set_charged_party { my $self = shift; - unless ( $self->charged_party ) { + my $conf = new FS::Conf; - my $conf = new FS::Conf; + unless ( $self->charged_party ) { if ( $conf->exists('cdr-charged_party-accountcode') && $self->accountcode ){ @@ -315,6 +315,14 @@ sub set_charged_party { } + my $prefix = $conf->config('cdr-charged_party-truncate_prefix'); + my $prefix_len = length($prefix); + my $trunc_len = $conf->config('cdr-charged_party-truncate_length'); + + $self->charged_party( substr($self->charged_party, 0, $trunc_len) ) + if $prefix_len && $trunc_len + && substr($self->charged_party, 0, $prefix_len) eq $prefix; + } =item set_status_and_rated_price STATUS [ RATED_PRICE ] -- cgit v1.2.1 From 521acd4c79757036fd2630f0a84e334be6b70484 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 9 May 2009 23:54:58 +0000 Subject: move cdr-sftp_and_import script to FS/bin, add -p option, RT#4081 --- FS/bin/freeside-cdr-sftp_and_import | 143 ++++++++++++++++++++++++++++++++++++ bin/cdr.sftp_and_import | 112 ---------------------------- 2 files changed, 143 insertions(+), 112 deletions(-) create mode 100755 FS/bin/freeside-cdr-sftp_and_import delete mode 100755 bin/cdr.sftp_and_import diff --git a/FS/bin/freeside-cdr-sftp_and_import b/FS/bin/freeside-cdr-sftp_and_import new file mode 100755 index 000000000..5786774d2 --- /dev/null +++ b/FS/bin/freeside-cdr-sftp_and_import @@ -0,0 +1,143 @@ +#!/usr/bin/perl + +use strict; +use Getopt::Std; +use Net::SFTP::Foreign; +use FS::UID qw(adminsuidsetup datasrc); +use FS::cdr; + +### +# parse command line +### + +use vars qw( $opt_p $opt_e $opt_d $opt_v ); +getopts('p:e:d:v'); + +$opt_e ||= 'csv'; +#$opt_e = ".$opt_e" unless $opt_e =~ /^\./; +$opt_e =~ s/^\.//; + +$opt_p ||= ''; + +my $user = shift or die &usage; +adminsuidsetup $user; + +# %%%FREESIDE_CACHE%%% +my $cachedir = '/usr/local/etc/freeside/cache.'. datasrc. '/cdrs'; +mkdir $cachedir unless -d $cachedir; + +my $format = shift or die &usage; + +use vars qw( $servername ); +$servername = shift or die &usage; + +### +# get the file list +### + +warn "Retreiving directory listing\n" if $opt_v; + +my $ls_sftp = sftp(); + +my $ls = $ls_sftp->ls('.', wanted => qr/^$opt_p.*\.$opt_e$/i ); + +### +# import each file +### + +foreach my $file ( @$ls ) { + + my $filename = $file->{filename}; + warn "Downloading $filename\n" if $opt_v; + + #get the file + my $get_sftp = sftp(); + $get_sftp->get($filename, "$cachedir/$filename") + or die "Can't get $filename: ". $get_sftp->error; + + warn "Processing $filename\n" if $opt_v; + + my $error = FS::cdr::batch_import( { + 'file' => "$cachedir/$filename", + 'format' => $format, + 'params' => { 'cdrbatch' => $filename, }, + 'empty_ok' => 1, + } ); + die $error if $error; + + if ( $opt_d ) { + my $mv_sftp = sftp(); + $mv_sftp->rename($filename, "$opt_d/$filename") + or die "can't move $filename to $opt_d: ". $mv_sftp->error; + } + + unlink "$cachedir/$filename"; + +} + +### +# subs +### + +sub usage { + "Usage: \n cdr.import user format servername\n"; +} + +use vars qw( $sftp ); + +sub sftp { + + #reuse connections + return $sftp if $sftp && $sftp->cwd; + + my %sftp = ( host => $servername ); + + #XXX remove these + $sftp{port} = 10022; + #$sftp{more} = '-v'; + + $sftp = Net::SFTP::Foreign->new(%sftp); + $sftp->error and die "SFTP connection failed: ". $sftp->error; + + $sftp; +} + +=head1 NAME + +cdr.sftp_and_import - Download CDR files from a remote server via SFTP + +=head1 SYNOPSIS + + cdr.sftp_and_import [ -p prefix ] [ -e extension ] [ -d donefolder ] [ -v ] user format [sftpuser@]servername + +=head1 DESCRIPTION + +Command line tool to download CDR files from a remote server via SFTP and then +import them into the database. + +-p: file prefix, if specified + +-e: file extension, defaults to .csv + +-d: if specified, moves files to the specified folder when done + +-v: verbose + +user: freeside username + +format: CDR format name + +[sftpuser@]servername: remote server + +=head1 BUGS + +Only supports SFTP right now. + +=head1 SEE ALSO + +L + +=cut + +1; + diff --git a/bin/cdr.sftp_and_import b/bin/cdr.sftp_and_import deleted file mode 100755 index 79e743f39..000000000 --- a/bin/cdr.sftp_and_import +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/perl -# -# Usage: -# cdr.sftp_and_import [ -e extension ] [ -d donefolder ] [ -v ] user format [sftpuser@]servername -# -# -e: file extension, defaults to .csv -# -d: if specified, moves files to the specified folder when done - -use strict; -use Getopt::Std; -use Net::SFTP::Foreign; -use FS::UID qw(adminsuidsetup datasrc); -use FS::cdr; - -### -# parse command line -### - -use vars qw( $opt_e $opt_d $opt_v ); -getopts('e:d:v'); - -$opt_e ||= 'csv'; -#$opt_e = ".$opt_e" unless $opt_e =~ /^\./; -$opt_e =~ s/^\.//; - -my $user = shift or die &usage; -adminsuidsetup $user; - -# %%%FREESIDE_CACHE%%% -my $cachedir = '/usr/local/etc/freeside/cache.'. datasrc. '/cdrs'; -mkdir $cachedir unless -d $cachedir; - -my $format = shift or die &usage; - -use vars qw( $servername ); -$servername = shift or die &usage; - -### -# get the file list -### - -warn "Retreiving directory listing\n" if $opt_v; - -my $ls_sftp = sftp(); - -my $ls = $ls_sftp->ls('.', wanted => qr/\.*$opt_e$/i ); - -### -# import each file -### - -foreach my $file ( @$ls ) { - - my $filename = $file->{filename}; - warn "Downloading $filename\n" if $opt_v; - - #get the file - my $get_sftp = sftp(); - $get_sftp->get($filename, "$cachedir/$filename") - or die "Can't get $filename: ". $get_sftp->error; - - warn "Processing $filename\n" if $opt_v; - - my $error = FS::cdr::batch_import( { - 'file' => "$cachedir/$filename" - 'format' => $format, - 'params' => { 'cdrbatch' => $filename, }, - 'empty_ok' => 1, - } ); - die $error if $error; - - close FILE; - - if ( $opt_d ) { - my $mv_sftp = sftp(); - $mv_sftp->rename($filename, "$opt_d/$filename") - or die "can't move $filename to $opt_d: ". $mv_sftp->error; - } - - unlink "$cachedir/$filename"; - -} - -1; - -### -# sub -### - -sub usage { - "Usage: \n cdr.import user format servername\n"; -} - -use vars qw( $sftp ); - -sub sftp { - - #reuse connections - return $sftp if $sftp && $sftp->cwd; - - my %sftp = ( host => $servername ); - - #XXX remove these - $sftp{port} = 10022; - #$sftp{more} = '-v'; - - $sftp = Net::SFTP::Foreign->new(%sftp); - $sftp->error and die "SFTP connection failed: ". $sftp->error; - - $sftp; -} - -- cgit v1.2.1 From eaf25d783191d2a6f14701442c491d78efd3b996 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 10 May 2009 00:45:33 +0000 Subject: label phone_name correctly --- FS/FS/svc_phone.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/svc_phone.pm b/FS/FS/svc_phone.pm index ce767d5ee..73ea8e731 100644 --- a/FS/FS/svc_phone.pm +++ b/FS/FS/svc_phone.pm @@ -102,7 +102,7 @@ sub table_info { disable_select => 1, }, 'sip_password' => 'SIP password', - 'name' => 'Name', + 'phone_name' => 'Name', }, }; } -- cgit v1.2.1 From 1b357798e052668efe0be9000a79e921e30141d2 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 13 May 2009 00:51:59 +0000 Subject: remove obsolete comments --- conf/invoice_latex | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/conf/invoice_latex b/conf/invoice_latex index 6f3665a03..0cd48125b 100644 --- a/conf/invoice_latex +++ b/conf/invoice_latex @@ -197,18 +197,7 @@ \begin{document} -% -%% Headers and footers defined for the first page -% -%% The LH Heading comprising logo -%% UNCOMMENT the following FOUR lines and change the path if necssary to provide a logo -% -%% The Heading comprising isue date, customer ref & INVOICE name -% -%% Header & footer changes for subsequent pages -% -% -% +% Headers and footers defined for the first page \addressinset \rule{0.5cm}{0cm} \makebox{ \begin{minipage}[t]{7.0cm} -- cgit v1.2.1 From 794a4505360fec404e2b9d5c6daf79f750186bfe Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 13 May 2009 22:27:42 +0000 Subject: improved taxproduct tax report RT#4783 --- FS/FS/Schema.pm | 32 +++- FS/FS/cust_bill_pkg.pm | 13 ++ FS/FS/cust_bill_pkg_tax_rate_location.pm | 136 ++++++++++++++ FS/FS/cust_main.pm | 25 +++ FS/FS/tax_rate.pm | 27 ++- FS/FS/tax_rate_location.pm | 309 +++++++++++++++++++++++++++++++ FS/MANIFEST | 4 + FS/t/cust_bill_pkg_tax_rate_location.t | 5 + FS/t/tax_rate_location.t | 5 + bin/tax_rate_location.import | 48 +++++ httemplate/misc/tax-import.cgi | 8 +- httemplate/search/cust_bill_pkg.cgi | 24 +++ httemplate/search/report_newtax.cgi | 105 +++++++---- 13 files changed, 695 insertions(+), 46 deletions(-) create mode 100644 FS/FS/cust_bill_pkg_tax_rate_location.pm create mode 100644 FS/FS/tax_rate_location.pm create mode 100644 FS/t/cust_bill_pkg_tax_rate_location.t create mode 100644 FS/t/tax_rate_location.t create mode 100755 bin/tax_rate_location.import diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index e70a12c1e..a9b546940 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -560,7 +560,7 @@ sub tables_hashref { 'billpkgtaxlocationnum', 'serial', '', '', '', '', 'billpkgnum', 'int', '', '', '', '', 'taxnum', 'int', '', '', '', '', - 'taxtype', 'varchar', $char_d, '', '', '', + 'taxtype', 'varchar', '', $char_d, '', '', 'pkgnum', 'int', '', '', '', '', 'locationnum', 'int', '', '', '', '', #redundant? 'amount', @money_type, '', '', @@ -570,6 +570,21 @@ sub tables_hashref { 'index' => [ [ 'billpkgnum' ], [ 'taxnum' ], [ 'pkgnum' ], [ 'locationnum' ] ], }, + 'cust_bill_pkg_tax_rate_location' => { + 'columns' => [ + 'billpkgtaxratelocationnum', 'serial', '', '', '', '', + 'billpkgnum', 'int', '', '', '', '', + 'taxnum', 'int', '', '', '', '', + 'taxtype', 'varchar', '', $char_d, '', '', + 'locationtaxid', 'varchar', 'NULL', $char_d, '', '', + 'taxratelocationnum', 'int', '', '', '', '', + 'amount', @money_type, '', '', + ], + 'primary_key' => 'billpkgtaxratelocationnum', + 'unique' => [], + 'index' => [ [ 'billpkgnum' ], [ 'taxnum' ], [ 'taxratelocationnum' ] ], + }, + 'cust_credit' => { 'columns' => [ 'crednum', 'serial', '', '', '', '', @@ -805,6 +820,21 @@ sub tables_hashref { 'index' => [ ['taxclassnum'], ['data_vendor', 'geocode'] ], }, + 'tax_rate_location' => { + 'columns' => [ + 'taxratelocationnum', 'serial', '', '', '', '', + 'data_vendor', 'varchar', 'NULL', $char_d, '', '', + 'geocode', 'varchar', '', 20, '', '', + 'city', 'varchar', 'NULL', $char_d, '', '', + 'county', 'varchar', 'NULL', $char_d, '', '', + 'state', 'char', '', 2, '', '', + 'disabled', 'char', 'NULL', 1, '', '', + ], + 'primary_key' => 'taxratelocationnum', + 'unique' => [], + 'index' => [ [ 'data_vendor', 'geocode', 'disabled' ] ], + }, + 'cust_tax_location' => { 'columns' => [ 'custlocationnum', 'serial', '', '', '', '', diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index 6c0589a5c..6bd39d4b9 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -162,6 +162,19 @@ sub insert { } } + my $tax_rate_location = $self->get('cust_bill_pkg_tax_rate_location'); + if ( $tax_rate_location ) { + foreach my $cust_bill_pkg_tax_rate_location ( @$tax_rate_location ) { + $cust_bill_pkg_tax_rate_location->billpkgnum($self->billpkgnum); + $error = $cust_bill_pkg_tax_rate_location->insert; + warn $error; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; diff --git a/FS/FS/cust_bill_pkg_tax_rate_location.pm b/FS/FS/cust_bill_pkg_tax_rate_location.pm new file mode 100644 index 000000000..fc5734fc1 --- /dev/null +++ b/FS/FS/cust_bill_pkg_tax_rate_location.pm @@ -0,0 +1,136 @@ +package FS::cust_bill_pkg_tax_rate_location; + +use strict; +use base qw( FS::Record ); +use FS::Record qw( qsearch qsearchs ); +use FS::cust_bill_pkg; +use FS::cust_pkg; +use FS::cust_location; + +=head1 NAME + +FS::cust_bill_pkg_tax_rate_location - Object methods for cust_bill_pkg_tax_rate_location records + +=head1 SYNOPSIS + + use FS::cust_bill_pkg_tax_rate_location; + + $record = new FS::cust_bill_pkg_tax_rate_location \%hash; + $record = new FS::cust_bill_pkg_tax_rate_location { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_bill_pkg_tax_rate_location object represents an record of taxation +based on package location. FS::cust_bill_pkg_tax_rate_location inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item billpkgtaxratelocationnum + +billpkgtaxratelocationnum + +=item billpkgnum + +billpkgnum + +=item taxnum + +taxnum + +=item taxtype + +taxtype + +=item locationtaxid + +locationtaxid + +=item taxratelocationnum + +taxratelocationnum + +=item amount + +amount + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new record. To add the record to the database, see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I method. + +=cut + +sub table { 'cust_bill_pkg_tax_rate_location'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=item check + +Checks all fields to make sure this is a valid record. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('billpkgtaxratelocationnum') + || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum' ) + || $self->ut_number('taxnum') #cust_bill_pkg/tax_rate key, based on taxtype + || $self->ut_enum('taxtype', [ qw( FS::cust_main_county FS::tax_rate ) ] ) + || $self->ut_textn('locationtaxid') + || $self->ut_foreign_key('taxratelocationnum', 'tax_rate_location', 'taxratelocationnum' ) + || $self->ut_money('amount') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 6f05fd5aa..a1bb926b3 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -30,6 +30,7 @@ use FS::cust_bill; use FS::cust_bill_pkg; use FS::cust_bill_pkg_display; use FS::cust_bill_pkg_tax_location; +use FS::cust_bill_pkg_tax_rate_location; use FS::cust_pay; use FS::cust_pay_pending; use FS::cust_pay_void; @@ -40,6 +41,7 @@ use FS::part_referral; use FS::cust_main_county; use FS::cust_location; use FS::tax_rate; +use FS::tax_rate_location; use FS::cust_tax_location; use FS::part_pkg_taxrate; use FS::agent; @@ -2461,6 +2463,10 @@ sub bill { # values are listrefs of cust_bill_pkg_tax_location hashrefs my %tax_location = (); + # keys are taxlisthash keys (internal identifiers) + # values are listrefs of cust_bill_pkg_tax_rate_location hashrefs + my %tax_rate_location = (); + foreach my $tax ( keys %taxlisthash ) { my $tax_object = shift @{ $taxlisthash{$tax} }; warn "found ". $tax_object->taxname. " as $tax\n" if $DEBUG > 2; @@ -2497,6 +2503,20 @@ sub bill { }; } + $tax_rate_location{ $tax } ||= []; + if ( ref($tax_object) eq 'FS::tax_rate' ) { + my $taxratelocationnum = + $tax_object->tax_rate_location->taxratelocationnum; + push @{ $tax_rate_location{ $tax } }, + { + 'taxnum' => $tax_object->taxnum, + 'taxtype' => ref($tax_object), + 'amount' => sprintf('%.2f', $amount ), + 'locationtaxid' => $tax_object->location, + 'taxratelocationnum' => $taxratelocationnum, + }; + } + } #move the cust_tax_exempt_pkg records to the cust_bill_pkgs we will commit @@ -2516,6 +2536,7 @@ sub bill { my $tax = 0; my %seen = (); my @cust_bill_pkg_tax_location = (); + my @cust_bill_pkg_tax_rate_location = (); warn "adding $taxname\n" if $DEBUG > 1; foreach my $taxitem ( @{ $taxname{$taxname} } ) { next if $seen{$taxitem}++; @@ -2524,6 +2545,9 @@ sub bill { push @cust_bill_pkg_tax_location, map { new FS::cust_bill_pkg_tax_location $_ } @{ $tax_location{ $taxitem } }; + push @cust_bill_pkg_tax_rate_location, + map { new FS::cust_bill_pkg_tax_rate_location $_ } + @{ $tax_rate_location{ $taxitem } }; } next unless $tax; @@ -2538,6 +2562,7 @@ sub bill { 'edate' => '', 'itemdesc' => $taxname, 'cust_bill_pkg_tax_location' => \@cust_bill_pkg_tax_location, + 'cust_bill_pkg_tax_rate_location' => \@cust_bill_pkg_tax_rate_location, }; } diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index dfa7d5f44..80a0f4b11 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -19,6 +19,7 @@ use FS::Record qw( qsearch qsearchs dbh dbdef ); use FS::tax_class; use FS::cust_bill_pkg; use FS::cust_tax_location; +use FS::tax_rate_location; use FS::part_pkg_taxrate; use FS::cust_main; use FS::Misc qw( csv_from_fixed ); @@ -538,6 +539,26 @@ sub tax_on_tax { } +=item tax_rate_location + +Returns an object representing the location associated with this tax +(see L) + +=cut + +sub tax_rate_location { + my $self = shift; + + qsearchs({ 'table' => 'tax_rate_location', + 'hashref' => { 'data_vendor' => $self->data_vendor, + 'geocode' => $self->geocode, + 'disabled' => '', + }, + }) || + new FS::tax_rate_location; + +} + =back =head1 SUBROUTINES @@ -845,7 +866,8 @@ sub process_batch_import { my $error = ''; my $have_location = 0; - my @list = ( 'CODE', 'codefile', \&FS::tax_class::batch_import, + my @list = ( 'GEOCODE', 'geofile', \&FS::tax_rate_location::batch_import, + 'CODE', 'codefile', \&FS::tax_class::batch_import, 'PLUS4', 'plus4file', \&FS::cust_tax_location::batch_import, 'ZIP', 'zipfile', \&FS::cust_tax_location::batch_import, 'TXMATRIX', 'txmatrix', \&FS::part_pkg_taxrate::batch_import, @@ -887,7 +909,8 @@ sub process_batch_import { my @insert_list = (); my @delete_list = (); - my @list = ( 'CODE', 'codefile', \&FS::tax_class::batch_import, + my @list = ( 'GEOCODE', 'geofile', \&FS::tax_rate_location::batch_import, + 'CODE', 'codefile', \&FS::tax_class::batch_import, 'PLUS4', 'plus4file', \&FS::cust_tax_location::batch_import, 'ZIP', 'zipfile', \&FS::cust_tax_location::batch_import, 'TXMATRIX', 'txmatrix', \&FS::part_pkg_taxrate::batch_import, diff --git a/FS/FS/tax_rate_location.pm b/FS/FS/tax_rate_location.pm new file mode 100644 index 000000000..65bef7bf7 --- /dev/null +++ b/FS/FS/tax_rate_location.pm @@ -0,0 +1,309 @@ +package FS::tax_rate_location; + +use strict; +use base qw( FS::Record ); +use FS::Record qw( qsearch qsearchs dbh ); + +=head1 NAME + +FS::tax_rate_location - Object methods for tax_rate_location records + +=head1 SYNOPSIS + + use FS::tax_rate_location; + + $record = new FS::tax_rate_location \%hash; + $record = new FS::tax_rate_location { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::tax_rate_location object represents an example. FS::tax_rate_location inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item taxratelocationnum + +Primary key (assigned automatically for new tax_rate_locations) + +=item data_vendor + +The tax data vendor + +=item geocode + +A unique geographic location code provided by the data vendor + +=item city + +City + +=item county + +County + +=item state + +State + +=item disabled + +If 'Y' this record is no longer active. + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new tax rate location. To add the record to the database, see + L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I method. + +=cut + +sub table { 'tax_rate_location'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +=item delete + +Delete this record from the database. + +=cut + +sub delete { + return "Can't delete tax rate locations. Set disable to 'Y' instead."; + # check that it is unused in any cust_bill_pkg_tax_location records instead? +} + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +=item check + +Checks all fields to make sure this is a valid tax rate location. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('taxratelocationnum') + || $self->ut_textn('data_vendor') + || $self->ut_alpha('geocode') + || $self->ut_textn('city') + || $self->ut_textn('county') + || $self->ut_textn('state') + || $self->ut_enum('disabled', [ '', 'Y' ]) + ; + return $error if $error; + + my $t = qsearchs( 'tax_rate_location', + { map { $_ => $self->$_ } qw( data_vendor geocode ) }, + ); + + return "geocode already in use for this vendor" + if ( $t && $t->taxratelocationnum != $self->taxratelocationnum ); + + return "may only be disabled" + if ( $t && scalar( grep { $t->$_ ne $self->$_ } + grep { $_ ne 'disabled' } + $self->fields + ) + ); + + $self->SUPER::check; +} + +=back + +=head1 SUBROUTINES + +=over 4 + +=item batch_import + +=cut + +sub batch_import { + my ($param, $job) = @_; + + my $fh = $param->{filehandle}; + my $format = $param->{'format'}; + + my %insert = (); + my %delete = (); + + my @fields; + my $hook; + + my @column_lengths = (); + my @column_callbacks = (); + if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) { + $format =~ s/-fixed//; + my $trim = sub { my $r = shift; $r =~ s/^\s*//; $r =~ s/\s*$//; $r }; + push @column_lengths, qw( 28 25 2 10 ); + push @column_lengths, 1 if $format eq 'cch-update'; + push @column_callbacks, $trim foreach (@column_lengths); + } + + my $line; + my ( $count, $last, $min_sec ) = (0, time, 5); #progressbar + if ( $job || scalar(@column_callbacks) ) { + my $error = + csv_from_fixed(\$fh, \$count, \@column_lengths, \@column_callbacks); + return $error if $error; + } + + if ( $format eq 'cch' || $format eq 'cch-update' ) { + @fields = qw( city county state geocode ); + push @fields, 'actionflag' if $format eq 'cch-update'; + + $hook = sub { + my $hash = shift; + + $hash->{'data_vendor'} ='cch'; + + if (exists($hash->{'actionflag'}) && $hash->{'actionflag'} eq 'D') { + delete($hash->{actionflag}); + + $hash->{deleted} = ''; + my $tax_rate_location = qsearchs('tax_rate_location', $hash); + return "Can't find tax_rate_location to delete: ". + join(" ", map { "$_ => ". $hash->{$_} } @fields) + unless $tax_rate_location; + + $tax_rate_location->disabled('Y'); + my $error = $tax_rate_location->replace; + return $error if $error; + + delete($hash->{$_}) foreach (keys %$hash); + } + + delete($hash->{'actionflag'}); + + ''; + + }; + + } elsif ( $format eq 'extended' ) { + die "unimplemented\n"; + @fields = qw( ); + $hook = sub {}; + } else { + die "unknown format $format"; + } + + eval "use Text::CSV_XS;"; + die $@ if $@; + + my $csv = new Text::CSV_XS; + + my $imported = 0; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + while ( defined($line=<$fh>) ) { + $csv->parse($line) or do { + $dbh->rollback if $oldAutoCommit; + return "can't parse: ". $csv->error_input(); + }; + + if ( $job ) { # progress bar + if ( time - $min_sec > $last ) { + my $error = $job->update_statustext( + int( 100 * $imported / $count ) + ); + die $error if $error; + $last = time; + } + } + + my @columns = $csv->fields(); + + my %tax_rate_location = (); + foreach my $field ( @fields ) { + $tax_rate_location{$field} = shift @columns; + } + if ( scalar( @columns ) ) { + $dbh->rollback if $oldAutoCommit; + return "Unexpected trailing columns in line (wrong format?): $line"; + } + + my $error = &{$hook}(\%tax_rate_location); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + if (scalar(keys %tax_rate_location)) { #inserts only + + my $tax_rate_location = new FS::tax_rate_location( \%tax_rate_location ); + $error = $tax_rate_location->insert; + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "can't insert tax_rate for $line: $error"; + } + + } + + $imported++; + + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + return "Empty file!" unless ($imported || $format eq 'cch-update'); + + ''; #no error + +} + +=head1 BUGS + +Currently somewhat specific to CCH supplied data. + +=head1 SEE ALSO + +L, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/MANIFEST b/FS/MANIFEST index 4b9fd91b5..b5c9046a6 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -434,3 +434,7 @@ FS/cust_location.pm t/cust_location.t FS/cust_bill_pkg_tax_location.pm t/cust_bill_pkg_tax_location.t +FS/tax_rate_location.pm +t/tax_rate_location.t +FS/cust_bill_pkg_tax_rate_location.pm +t/cust_bill_pkg_tax_rate_location.t diff --git a/FS/t/cust_bill_pkg_tax_rate_location.t b/FS/t/cust_bill_pkg_tax_rate_location.t new file mode 100644 index 000000000..3250db9b5 --- /dev/null +++ b/FS/t/cust_bill_pkg_tax_rate_location.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::cust_bill_pkg_tax_rate_location; +$loaded=1; +print "ok 1\n"; diff --git a/FS/t/tax_rate_location.t b/FS/t/tax_rate_location.t new file mode 100644 index 000000000..f4ee910a0 --- /dev/null +++ b/FS/t/tax_rate_location.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::tax_rate_location; +$loaded=1; +print "ok 1\n"; diff --git a/bin/tax_rate_location.import b/bin/tax_rate_location.import new file mode 100755 index 000000000..439d27cc9 --- /dev/null +++ b/bin/tax_rate_location.import @@ -0,0 +1,48 @@ +#!/usr/bin/perl -Tw + +use strict; +use vars qw($opt_g $opt_f); +use vars qw($DEBUG); +use Getopt::Std; +use FS::UID qw(adminsuidsetup); +use FS::Conf; +use FS::tax_rate_location; + +getopts('f:g:'); + +my $user = shift or die &usage; +my $dbh = adminsuidsetup $user; + +my ($format) = $opt_f =~ /^([-\w]+)$/; + +my @list = ( + 'GEOCODE', $opt_g, \&FS::tax_rate_location::batch_import, +); + +my $oldAutoCommit = $FS::UID::AutoCommit; +local $FS::UID::AutoCommit = 0; + +my $error = ''; + +while(@list) { + my ($name, $file, $method) = splice(@list, 0, 3); + + my $fh; + + $file =~ /^([\s\d\w.]+)$/ or die "Illegal filename: $file\n"; + $file = $1; + + open $fh, '<', $file or die "can't open $name file: $!\n"; + $error ||= &{$method}( { filehandle => $fh, 'format' => $format, } ); + + die "error while processing $file: $error" if $error; + close $fh; +} + +if ($error) { + $dbh->rollback or die $dbh->errstr if $oldAutoCommit; +}else{ + $dbh->commit or die $dbh->errstr if $oldAutoCommit; +} + +sub usage { die "Usage:\ntax_rates_location.import -f FORMAT -g GEOCODEFILE user\n\n"; } diff --git a/httemplate/misc/tax-import.cgi b/httemplate/misc/tax-import.cgi index a695e9706..5116e5404 100644 --- a/httemplate/misc/tax-import.cgi +++ b/httemplate/misc/tax-import.cgi @@ -6,7 +6,7 @@ Import a CSV file set containing tax rate records. <% include( '/elements/form-file_upload.html', 'name' => 'TaxRateUpload', 'action' => 'process/tax-import.cgi', - 'num_files' => 5, + 'num_files' => 6, 'fields' => [ 'format', ], 'message' => 'Tax rates imported', ) @@ -27,13 +27,15 @@ Import a CSV file set containing tax rate records. <% include( '/elements/file-upload.html', - 'field' => [ 'codefile', + 'field' => [ 'geofile', + 'codefile', 'plus4file', 'zipfile', 'txmatrix', 'detail', ], - 'label' => [ 'code filename', + 'label' => [ 'geocode filename', + 'code filename', 'plus4 filename', 'zip filename', 'txmatrix filename', diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi index 89901ac40..9d4843281 100644 --- a/httemplate/search/cust_bill_pkg.cgi +++ b/httemplate/search/cust_bill_pkg.cgi @@ -189,6 +189,26 @@ if ( $cgi->param('out') ) { } + } elsif ( scalar( grep( /locationtaxid/, $cgi->param ) ) ) { + + # this should really be shoved out to FS::cust_pkg->location_sql or something + # along with the code in report_newtax.cgi + + my %pn = ( + 'county' => 'tax_rate_location.county', + 'state' => 'tax_rate_location.state', + 'city' => 'tax_rate_location.city', + 'locationtaxid' => 'cust_bill_pkg_tax_rate_location.locationtaxid', + ); + + my %ph = map { ( $pn{$_} => dbh->quote( $cgi->param($_) || '' ) ) } + qw( county state city locationtaxid ); + + push @where, + join( ' AND ', map { "( $_ = $ph{$_} OR $ph{$_} = '' AND $_ IS NULL)" } + keys %ph + ); + } if ($cgi->param('itemdesc')) { @@ -295,6 +315,10 @@ if ( $cgi->param('nottax') ) { #quelle kludge, false laziness w/report_tax.cgi $where =~ s/cust_pkg\.locationnum/cust_bill_pkg_tax_location.locationnum/g; + } elsif ( scalar( grep( /locationtaxid/, $cgi->param ) ) ) { + $join_pkg .= + ' LEFT JOIN cust_bill_pkg_tax_rate_location USING ( billpkgnum ) '. + ' LEFT JOIN tax_rate_location USING ( taxratelocationnum ) '; } } else { diff --git a/httemplate/search/report_newtax.cgi b/httemplate/search/report_newtax.cgi index 586fddd25..0fb548352 100755 --- a/httemplate/search/report_newtax.cgi +++ b/httemplate/search/report_newtax.cgi @@ -14,6 +14,7 @@ <% include('/elements/table-grid.html') %> + Tax collected @@ -37,9 +38,11 @@ <% $tax->{'label'} %> + <% $tax->{base} ? qq!! : '' %> <% $money_char %><% sprintf('%.2f', $tax->{'tax'} ) %> + <% !($tax->{base}) ? qq!! : '' %> % } @@ -61,10 +64,11 @@ my $join_cust = " JOIN cust_bill USING ( invnum ) LEFT JOIN cust_main USING ( custnum ) "; -my $from_join_cust = " - FROM cust_bill_pkg - $join_cust -"; + +my $join_loc = "LEFT JOIN cust_bill_pkg_tax_rate_location USING ( billpkgnum )"; +my $join_tax_loc = "LEFT JOIN tax_rate_location USING ( taxratelocationnum )"; + +my $addl_from = " $join_cust $join_loc $join_tax_loc "; my $where = "WHERE _date >= $beginning AND _date <= $ending "; @@ -76,65 +80,87 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { $where .= ' AND cust_main.agentnum = '. $agent->agentnum; } +# my ( $location_sql, @location_param ) = FS::cust_pkg->location_sql; +# $where .= " AND $location_sql"; +#my @taxparam = ( 'itemdesc', @location_param ); +# now something along the lines of geocode matching ? +#$where .= FS::cust_pkg->_location_sql_where('cust_tax_location');; +my @taxparam = ( 'itemdesc', 'tax_rate_location.state', 'tax_rate_location.county', 'tax_rate_location.city', 'cust_bill_pkg_tax_rate_location.locationtaxid' ); + +my $select = 'DISTINCT itemdesc,locationtaxid,tax_rate_location.state,tax_rate_location.county,tax_rate_location.city'; + my $tax = 0; my %taxes = (); +my %basetaxes = (); foreach my $t (qsearch({ table => 'cust_bill_pkg', + select => $select, hashref => { pkgpart => 0 }, - addl_from => $join_cust, + addl_from => $addl_from, extra_sql => $where, }) ) { - #warn $t->itemdesc. "\n"; + my @params = map { my $f = $_; $f =~ s/.*\.//; $f } @taxparam; + my $label = join('~', map { $t->$_ } @params); + $label = 'Tax'. $label if $label =~ /^~/; + unless ( exists( $taxes{$label} ) ) { + my ($baselabel, @trash) = split /~/, $label; - my $label = $t->itemdesc; - $label ||= 'Tax'; - $taxes{$label}->{'label'} = $label; - $taxes{$label}->{'url_param'} = "itemdesc=$label"; + $taxes{$label}->{'label'} = join(', ', split(/~/, $label) ); + $taxes{$label}->{'url_param'} = + join(';', map { "$_=". uri_escape($t->$_) } @params); - # calculate total for this tax - # calculate customer-exemption for this tax - # calculate package-exemption for this tax - # calculate monthly exemption (texas tax) for this tax - # count up all the cust_tax_exempt_pkg records associated with - # the actual line items. -} + my $taxwhere = "FROM cust_bill_pkg $addl_from $where AND payby != 'COMP' ". + "AND ". join( ' AND ', map { "( $_ = ? OR ? = '' AND $_ IS NULL)" } @taxparam ); + my $sql = "SELECT SUM(cust_bill_pkg.setup+cust_bill_pkg.recur) ". + " $taxwhere AND cust_bill_pkg.pkgnum = 0"; -foreach my $t (qsearch({ table => 'cust_bill_pkg', - select => 'DISTINCT itemdesc', - hashref => { pkgpart => 0 }, - addl_from => $join_cust, - extra_sql => $where, - }) - ) -{ + my $x = scalar_sql($t, [ map { $_, $_ } @params ], $sql ); + $tax += $x; + $taxes{$label}->{'tax'} += $x; + + unless ( exists( $taxes{$baselabel} ) ) { - my $label = $t->itemdesc; - $label ||= 'Tax'; - my @taxparam = ( 'itemdesc' ); - my $taxwhere = "$from_join_cust $where AND payby != 'COMP' ". - "AND itemdesc = ?" ; + $basetaxes{$baselabel}->{'label'} = $baselabel; + $basetaxes{$baselabel}->{'url_param'} = "itemdesc=$baselabel"; + $basetaxes{$baselabel}->{'base'} = 1; - my $sql = "SELECT SUM(cust_bill_pkg.setup+cust_bill_pkg.recur) ". - " $taxwhere AND pkgnum = 0"; + } - my $x = scalar_sql($t, \@taxparam, $sql ); - $tax += $x; - $taxes{$label}->{'tax'} += $x; + $basetaxes{$baselabel}->{'tax'} += $x; + + } + # calculate customer-exemption for this tax + # calculate package-exemption for this tax + # calculate monthly exemption (texas tax) for this tax + # count up all the cust_tax_exempt_pkg records associated with + # the actual line items. } + #ordering -my @taxes = - map $taxes{$_}, - sort { ($b cmp $a) } - keys %taxes; +my @taxes = (); + +foreach my $tax ( sort { $a cmp $b } keys %taxes ) { + my ($base, @trash) = split '~', $tax; + my $basetax = delete( $basetaxes{$base} ); + if ($basetax) { + if ( $basetax->{tax} == $taxes{$tax}->{tax} ) { + $taxes{$tax}->{base} = 1; + } else { + push @taxes, $basetax; + } + } + push @taxes, $taxes{$tax}; +} push @taxes, { 'label' => 'Total', 'url_param' => '', 'tax' => $tax, + 'base' => 1, }; #-- @@ -143,7 +169,6 @@ push @taxes, { #to FS::Report or FS::Record or who the fuck knows where) sub scalar_sql { my( $r, $param, $sql ) = @_; - #warn "$sql\n"; my $sth = dbh->prepare($sql) or die dbh->errstr; $sth->execute( map $r->$_(), @$param ) or die "Unexpected error executing statement $sql: ". $sth->errstr; -- cgit v1.2.1 From 7923b92cdd671e1b13c951af33c11b0ac25dd894 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 14 May 2009 16:25:21 +0000 Subject: show geocode when taxproducts enabled --- httemplate/view/cust_main/billing.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index aea90e8b3..4b2425b33 100644 --- a/httemplate/view/cust_main/billing.html +++ b/httemplate/view/cust_main/billing.html @@ -164,6 +164,12 @@ Billing information Tax exempt <% $cust_main->tax ? 'yes' : 'no' %> +% if ( $conf->exists('enable_taxproducts') ) { + + Tax location + <% $cust_main->geocode('cch') %> + +% } Postal invoices -- cgit v1.2.1 From 5f675c352a10f555de5831bb76ab00b35b6b9bd1 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 14 May 2009 16:26:40 +0000 Subject: ask for help assignting geocode more often --- httemplate/edit/cust_main/bottomfixup.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js index efe2215c8..ae4aafb70 100644 --- a/httemplate/edit/cust_main/bottomfixup.js +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -59,6 +59,7 @@ function update_address(arg) { var ship_changed = argsHash['ship_address_standardized']; var error = argsHash['error']; var ship_error = argsHash['ship_error']; + //yay closures standardize_address = function () { @@ -91,7 +92,9 @@ function update_address(arg) { % if ( $conf->exists('enable_taxproducts') ) { - if ( <% $taxpre %>error ) { + if ( <% $taxpre %>error || + new String(argsHash['new_<% $taxpre %>zip']).length < 10 ) + { var country_el = cf.elements['<% $taxpre %>country']; var country = country_el.options[ country_el.selectedIndex ].value; -- cgit v1.2.1 From ad84bf7cfdb56aa1fe268ea315b7a2f7dd768db2 Mon Sep 17 00:00:00 2001 From: rsiddall Date: Fri, 15 May 2009 19:41:34 +0000 Subject: Simple domain registration at Tucows OpenSRS using an export based on Net::OpenSRS. When a domain is added and the export runs, it will register the domain or initiate a transfer. You can also choose no action. There's currently no provision for revoking domains or renewing registrations. Depending on the settings at OpenSRS, orders may look like they've succeeded in Freeside but actually be queued pending input by the reseller at OpenSRS. The part_export CGIs were modified to allow a multi-valued select to be used to control which TLDs are enabled for registration. --- FS/FS/part_export/domreg_opensrs.pm | 245 ++++++++++++++++++++++++++++++++ FS/FS/svc_domain.pm | 1 - httemplate/edit/part_export.cgi | 23 ++- httemplate/edit/process/part_export.cgi | 3 +- httemplate/edit/process/svc_domain.cgi | 4 +- httemplate/edit/svc_domain.cgi | 42 ++++-- 6 files changed, 302 insertions(+), 16 deletions(-) create mode 100644 FS/FS/part_export/domreg_opensrs.pm diff --git a/FS/FS/part_export/domreg_opensrs.pm b/FS/FS/part_export/domreg_opensrs.pm new file mode 100644 index 000000000..ec73d3ce5 --- /dev/null +++ b/FS/FS/part_export/domreg_opensrs.pm @@ -0,0 +1,245 @@ +package FS::part_export::domreg_opensrs; + +use vars qw(@ISA %info %options $conf); +use Tie::IxHash; +use FS::Record qw(qsearchs qsearch); +use FS::Conf; +use FS::part_export::null; +use FS::svc_domain; +use FS::part_pkg; +use Net::OpenSRS; + +=head1 NAME + +FS::part_export::domreg_opensrs - Register or transfer domains with Tucows OpenSRS + +=head1 DESCRIPTION + +This module handles registering and transferring domains using a registration service provider (RSP) account +at Tucows OpenSRS, an ICANN-approved domain registrar. + +As a part_export, this module can be designated for use with svc_domain services. When the svc_domain object +is inserted into the Freeside database, registration or transferring of the domain may be initiated, depending +on the setting of the svc_domain's action field. + +=over 4 + +=item N - Register the domain + +=item M - Transfer the domain + +=item I - Ignore the domain for registration purposes + +=back + +=cut + +@ISA = qw(FS::part_export::null); + +my @tldlist = qw/com net org biz info name mobi at be ca cc ch cn de dk es eu fr it mx nl tv uk us/; + +tie %options, 'Tie::IxHash', + 'username' => { label => 'Reseller user name at OpenSRS', + }, + 'privatekey' => { label => 'Private key', + }, + 'password' => { label => 'Password for management account', + }, + 'masterdomain' => { label => 'Master domain at OpenSRS', + }, + 'debug_level' => { label => 'Net::OpenSRS debug level', + type => 'select', + options => [ 0, 1, 2, 3 ], + default => 0 }, + 'register' => { label => 'Use for registration', + type => 'checkbox', + default => '1' }, + 'transfer' => { label => 'Use for transfer', + type => 'checkbox', + default => '1' }, + 'tlds' => { label => 'Use this export for these top-level domains (TLDs)', + type => 'select', + multi => 1, + size => scalar(@tldlist), + options => [ @tldlist ], + default => 'com net org' }, +; + +%info = ( + 'svc' => 'svc_domain', + 'desc' => 'Domain registration via Tucows OpenSRS', + 'options' => \%options, + 'notes' => <<'END' +Registers and transfers domains via the Tucows OpenSRS registrar (using Net::OpenSRS). +All of the Net::OpenSRS restrictions apply: +
    +
  • You must have a reseller account with Tucows. +
  • You must add the public IP address of the Freeside server to the 'Script API allow' list in the OpenSRS web interface. +
  • You must generate an API access key in the OpenSRS web interface and enter it below. +
  • All domains are managed using the same user name and password, but you can create sub-accounts for clients. +
  • The user name must be the same as your OpenSRS reseller ID. +
  • You must enter a master domain that all other domains are associated with. That domain must be registered through your OpenSRS account. +
+Some top-level domains offered by OpenSRS have additional business rules not supported by this export. These TLDs cannot be registered or transfered with this export. +

Use these buttons for some useful presets: +
    +
  • + +
  • + +
+END +); + +install_callback FS::UID sub { + $conf = new FS::Conf; +}; + +=head1 METHODS + +=over 4 + +=item format_tel + +Reformats a phone number according to registry rules. Currently Freeside stores phone numbers +in NANPA format and the registry prefers "+CCC.NPANPXNNNN" + +=cut + +sub format_tel { + my $tel = shift; + + #if ($tel =~ /^(\d{3})-(\d{3})-(\d{4})( x(\d+))?$/) { + if ($tel =~ /^(\d{3})-(\d{3})-(\d{4})$/) { + $tel = "+1.$1$2$3"; +# if $tel .= "$4" if $4; + } + return $tel; +} + +sub gen_contact_info +{ + my ($co)=@_; + + my @invoicing_list = $co->invoicing_list_emailonly; + if ( $conf->exists('emailinvoiceautoalways') + || $conf->exists('emailinvoiceauto') && ! @invoicing_list + || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) { + push @invoicing_list, $co->all_emails; + } + + my $email = ($conf->exists('business-onlinepayment-email-override')) + ? $conf->config('business-onlinepayment-email-override') + : $invoicing_list[0]; + + my $c = { + firstname => $co->first, + lastname => $co->last, + company => $co->company, + address => $co->address1, + city => $co->city(), + state => $co->state(), + zip => $co->zip(), + country => uc($co->country()), + email => $email, + #phone => format_tel($co->daytime()), + phone => $co->daytime() || $co->night, + }; + return $c; +} + +sub testmode { + my $self = shift; + + return 'live' if $self->machine eq "rr-n1-tor.opensrs.net"; + return 'test' if $self->machine eq "horizon.opensrs.net"; + undef; +} + +sub _export_insert { + my( $self, $svc_domain ) = ( shift, shift ); + + return if $svc_domain->action eq 'I'; # Ignoring registration, just doing DNS + + # Get the TLD of the new domain + my @bits = split /\./, $svc_domain->domain; + + return "Can't register subdomains: " . $svc_domain->domain if scalar(@bits) != 2; + + my $tld = pop @bits; + + # See if it's one this export supports + my @tlds = split /\s+/, $self->option('tlds'); + @tlds = map { s/\.//; $_ } @tlds; + return "Can't register top-level domain $tld, restricted to: " . $self->option('tlds') if ! grep { $_ eq $tld } @tlds; + + my $cust_main = $svc_domain->cust_svc->cust_pkg->cust_main; + + my $c = gen_contact_info($cust_main); + + my $srs = Net::OpenSRS->new(); + + $srs->debug_level( $self->option('debug_level') ); # Output should be in the Apache error log + + $srs->environment( $self->testmode() ); + $srs->set_key( $self->option('privatekey') ); + + $srs->set_manage_auth( $self->option('username'), $self->option('password') ); + + my $cookie = $srs->get_cookie( $self->option('masterdomain') ); + if (!$cookie) { + return "Unable to get cookie at OpenSRS: " . $srs->last_response(); + } + + if ($svc_domain->action eq 'N') { + return "Domain registration not enabled" if !$self->option('register'); + return $srs->last_response() if !$srs->register_domain( $svc_domain->domain, $c); + } elsif ($svc_domain->action eq 'M') { + return "Domain transfer not enabled" if !$self->option('transfer'); + return $srs->last_response() if !$srs->transfer_domain( $svc_domain->domain, $c); + } else { + return "Unknown domain action " . $svc_domain->action; + } + + return ''; # Should only get here if register or transfer succeeded + +} + +## Domain registration exports do nothing on replace. Mainly because we haven't decided what they should do. +#sub _export_replace { +# my( $self, $new, $old ) = (shift, shift, shift); +# +# return ''; +# +#} + +## Domain registration exports do nothing on delete. You're just removing the domain from Freeside, not the registry +#sub _export_delete { +# my( $self, $svc_domain ) = ( shift, shift ); +# +# return ''; +#} + +sub registrar { + return { + name => 'OpenSRS', + }; +} + +=back + +=head1 SEE ALSO + +L, L, L, +L, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm index 47aa8f32e..dd4f2c52f 100644 --- a/FS/FS/svc_domain.pm +++ b/FS/FS/svc_domain.pm @@ -388,7 +388,6 @@ sub check { or $self->ut_numbern('setup_date') or $self->ut_numbern('renewal_interval') or $self->ut_numbern('expiration_date') - or $self->ut_textn('purpose') or $self->SUPER::check; } diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi index d57979751..8b697e142 100644 --- a/httemplate/edit/part_export.cgi +++ b/httemplate/edit/part_export.cgi @@ -79,13 +79,28 @@ my $widget = new HTML::Widgets::SelectLayers( ); $html .= qq!$label!; if ( $type eq 'select' ) { - $html .= qq!!; + my @values = split '\s+', $value if $multi; + my @options; + if (defined($optinfo->{option_values})) { + my $valsub = $optinfo->{option_values}; + @options = &$valsub(); + } elsif (defined($optinfo->{options})) { + @options = @{$optinfo->{options}}; + } + foreach my $select_option ( @options ) { #if ( ref($select_option) ) { #} else { - my $selected = $select_option eq $value ? ' SELECTED' : ''; + my $selected = ($multi ? grep {$_ eq $select_option} @values : $select_option eq $value ) ? ' SELECTED' : ''; + my $label = $select_option; + if (defined($optinfo->{option_label})) { + my $labelsub = $optinfo->{option_label}; + $label = &$labelsub($select_option); + } $html .= qq!!; + qq!$label!; #} } $html .= ''; diff --git a/httemplate/edit/process/part_export.cgi b/httemplate/edit/process/part_export.cgi index b5f82e892..209419f0b 100644 --- a/httemplate/edit/process/part_export.cgi +++ b/httemplate/edit/process/part_export.cgi @@ -16,7 +16,8 @@ my $old = qsearchs('part_export', { 'exportnum'=>$exportnum } ) if $exportnum; #fixup options #warn join('-', split(',',$cgi->param('options'))); my %options = map { - my $value = $cgi->param($_); + my @values = $cgi->param($_); + my $value = scalar(@values) > 1 ? join (' ', @values) : $values[0]; $value =~ s/\r\n/\n/g; #browsers? (textarea) $_ => $value; } split(',', $cgi->param('options')); diff --git a/httemplate/edit/process/svc_domain.cgi b/httemplate/edit/process/svc_domain.cgi index 9993a879e..59b518097 100755 --- a/httemplate/edit/process/svc_domain.cgi +++ b/httemplate/edit/process/svc_domain.cgi @@ -18,8 +18,8 @@ my $svcnum = $1; my $new = new FS::svc_domain ( { map { $_, scalar($cgi->param($_)); - #} qw(svcnum pkgnum svcpart domain action purpose) - } ( fields('svc_domain'), qw( pkgnum svcpart action purpose ) ) + #} qw(svcnum pkgnum svcpart domain action) + } ( fields('svc_domain'), qw( pkgnum svcpart action ) ) } ); my $error = ''; diff --git a/httemplate/edit/svc_domain.cgi b/httemplate/edit/svc_domain.cgi index 56ba604bf..10079ce98 100755 --- a/httemplate/edit/svc_domain.cgi +++ b/httemplate/edit/svc_domain.cgi @@ -7,17 +7,31 @@ ->New +<% ntable("#cccccc",2) %> + +

Domain
+% if ($export) { +Available top-level domains: <% $export->option('tlds') %> + ->Transfer + +>Register at <% $registrar->{'name'} %> +
-

Domain +>Transfer to <% $registrar->{'name'} %> +
-
Purpose/Description: +>Registered elsewhere -

+ + +% } + +

+ + <% include('/elements/footer.html') %> @@ -27,7 +41,7 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? -my($svcnum, $pkgnum, $svcpart, $kludge_action, $purpose, $part_svc, +my($svcnum, $pkgnum, $svcpart, $kludge_action, $part_svc, $svc_domain); if ( $cgi->param('error') ) { @@ -38,7 +52,6 @@ if ( $cgi->param('error') ) { $pkgnum = $cgi->param('pkgnum'); $svcpart = $cgi->param('svcpart'); $kludge_action = $cgi->param('action'); - $purpose = $cgi->param('purpose'); $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } ); die "No part_svc entry!" unless $part_svc; @@ -61,7 +74,6 @@ if ( $cgi->param('error') ) { } else { #editing $kludge_action = ''; - $purpose = ''; my($query) = $cgi->keywords; $query =~ /^(\d+)$/ or die "unparsable svcnum"; $svcnum=$1; @@ -82,6 +94,20 @@ my $action = $svcnum ? 'Edit' : 'Add'; my $svc = $part_svc->getfield('svc'); +my @exports = $part_svc->part_export(); + +my $registrar; +my $export; + +# Find the first export that does domain registration +foreach (@exports) { + $export = $_ if $_->can('registrar'); +} +# If we have a domain registration export, get the registrar object +if ($export) { + $registrar = $export->registrar; +} + my $otaker = getotaker; my $domain = $svc_domain->domain; -- cgit v1.2.1 From 4f1256b03a041ddf12faa8e7891065ad5e1e9399 Mon Sep 17 00:00:00 2001 From: rsiddall Date: Sat, 16 May 2009 02:29:54 +0000 Subject: Provide better diagnostics when the cust_main owning this domain does not provide fields required for use as a contact handle in the domain registration record. Also temporarily disable the ability to have the export do only registration or only transfers. --- FS/FS/part_export/domreg_opensrs.pm | 45 ++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/FS/FS/part_export/domreg_opensrs.pm b/FS/FS/part_export/domreg_opensrs.pm index ec73d3ce5..5d5c59530 100644 --- a/FS/FS/part_export/domreg_opensrs.pm +++ b/FS/FS/part_export/domreg_opensrs.pm @@ -51,12 +51,12 @@ tie %options, 'Tie::IxHash', type => 'select', options => [ 0, 1, 2, 3 ], default => 0 }, - 'register' => { label => 'Use for registration', - type => 'checkbox', - default => '1' }, - 'transfer' => { label => 'Use for transfer', - type => 'checkbox', - default => '1' }, +# 'register' => { label => 'Use for registration', +# type => 'checkbox', +# default => '1' }, +# 'transfer' => { label => 'Use for transfer', +# type => 'checkbox', +# default => '1' }, 'tlds' => { label => 'Use this export for these top-level domains (TLDs)', type => 'select', multi => 1, @@ -154,6 +154,32 @@ sub gen_contact_info return $c; } +sub validate_contact_info { + my $c = shift; + + my %fields = ( + firstname => "first name", + lastname => "last name", + address => "street address", + city => "city", + state => "state", + zip => "ZIP/postal code", + country => "country", + email => "email address", + phone => "phone number", + ); + my @err = (); + foreach (keys %fields) { + if (!defined($c->{$_}) || !$c->{$_}) { + push @err, $fields{$_}; + } + } + if (scalar(@err) > 0) { + return "Contact information needs: " . join(', ', @err); + } + undef; +} + sub testmode { my $self = shift; @@ -183,6 +209,9 @@ sub _export_insert { my $c = gen_contact_info($cust_main); + my $err = validate_contact_info($c); + return $err if $err; + my $srs = Net::OpenSRS->new(); $srs->debug_level( $self->option('debug_level') ); # Output should be in the Apache error log @@ -198,10 +227,10 @@ sub _export_insert { } if ($svc_domain->action eq 'N') { - return "Domain registration not enabled" if !$self->option('register'); +# return "Domain registration not enabled" if !$self->option('register'); return $srs->last_response() if !$srs->register_domain( $svc_domain->domain, $c); } elsif ($svc_domain->action eq 'M') { - return "Domain transfer not enabled" if !$self->option('transfer'); +# return "Domain transfer not enabled" if !$self->option('transfer'); return $srs->last_response() if !$srs->transfer_domain( $svc_domain->domain, $c); } else { return "Unknown domain action " . $svc_domain->action; -- cgit v1.2.1 From c196542418599a740405d37454b529d5c98276be Mon Sep 17 00:00:00 2001 From: rsiddall Date: Sat, 16 May 2009 19:27:44 +0000 Subject: Defer use of Net::OpenSRS so that failure to install the module doesn't stop Apache from starting. (This causes attempts to register domains to fail instead.) --- FS/FS/part_export/domreg_opensrs.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/FS/FS/part_export/domreg_opensrs.pm b/FS/FS/part_export/domreg_opensrs.pm index 5d5c59530..df8b40006 100644 --- a/FS/FS/part_export/domreg_opensrs.pm +++ b/FS/FS/part_export/domreg_opensrs.pm @@ -7,7 +7,6 @@ use FS::Conf; use FS::part_export::null; use FS::svc_domain; use FS::part_pkg; -use Net::OpenSRS; =head1 NAME @@ -193,6 +192,9 @@ sub _export_insert { return if $svc_domain->action eq 'I'; # Ignoring registration, just doing DNS + eval "use Net::OpenSRS;"; + return $@ if $@; + # Get the TLD of the new domain my @bits = split /\./, $svc_domain->domain; -- cgit v1.2.1 From 63f161eddc1d6a832ef07a43e1bc232770f5f598 Mon Sep 17 00:00:00 2001 From: rsiddall Date: Sat, 16 May 2009 20:07:01 +0000 Subject: Added information on common failure causes to the perldoc. --- FS/FS/part_export/domreg_opensrs.pm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/FS/FS/part_export/domreg_opensrs.pm b/FS/FS/part_export/domreg_opensrs.pm index df8b40006..0ef371a7b 100644 --- a/FS/FS/part_export/domreg_opensrs.pm +++ b/FS/FS/part_export/domreg_opensrs.pm @@ -31,6 +31,10 @@ on the setting of the svc_domain's action field. =back +This export uses Net::OpenSRS. Registration and transfer attempts will fail unless Net::OpenSRS is installed +and LWP::UserAgent is able to make HTTPS posts. You can turn on debugging messages and use the OpenSRS test +gateway when setting up this export. + =cut @ISA = qw(FS::part_export::null); @@ -267,9 +271,10 @@ sub registrar { =head1 SEE ALSO -L, L, L, +L, L, L, L, L, schema.html from the base documentation. + =cut 1; -- cgit v1.2.1 From f6dd863ff944a162b2f135e820c7932b2615e332 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 18 May 2009 04:56:15 +0000 Subject: handle dates before 1970 --- FS/FS/part_pkg_taxrate.pm | 11 +++++++++-- FS/FS/tax_rate.pm | 12 ++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/FS/FS/part_pkg_taxrate.pm b/FS/FS/part_pkg_taxrate.pm index bc1047ee2..5a1e7baa9 100644 --- a/FS/FS/part_pkg_taxrate.pm +++ b/FS/FS/part_pkg_taxrate.pm @@ -3,6 +3,8 @@ package FS::part_pkg_taxrate; use strict; use vars qw( @ISA ); use Date::Parse; +use DateTime; +use DateTime::Format::Strptime; use FS::UID qw(dbh); use FS::Record qw( qsearch qsearchs ); use FS::part_pkg_taxproduct; @@ -181,7 +183,7 @@ sub batch_import { if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) { $format =~ s/-fixed//; my $date_format = sub { my $r=''; - /^(\d{4})(\d{2})(\d{2})$/ && ($r="$1/$2/$3"); + /^(\d{4})(\d{2})(\d{2})$/ && ($r="$3/$2/$1"); $r; }; $column_callbacks[16] = $date_format; @@ -286,7 +288,12 @@ sub batch_import { delete($hash->{$_}) foreach @{$map{$item}}; } - $hash->{'effdate'} = str2time($hash->{'effdate'}); + my $parser = new DateTime::Format::Strptime( pattern => "%m/%d/%Y", + time_zone => 'floating', + ); + my $dt = $parser->parse_datetime( $hash->{'effdate'} ); + $hash->{'effdate'} = $dt ? $dt->epoch : ''; + $hash->{'country'} = 'US'; # CA is available delete($hash->{'taxable'}) if ($hash->{'taxable'} eq 'N'); diff --git a/FS/FS/tax_rate.pm b/FS/FS/tax_rate.pm index 80a0f4b11..887c9af2c 100644 --- a/FS/FS/tax_rate.pm +++ b/FS/FS/tax_rate.pm @@ -5,6 +5,8 @@ use vars qw( @ISA $DEBUG $me %tax_unittypes %tax_maxtypes %tax_basetypes %tax_authorities %tax_passtypes %GetInfoType ); use Date::Parse; +use DateTime; +use DateTime::Format::Strptime; use Storable qw( thaw ); use IO::File; use File::Temp; @@ -586,7 +588,7 @@ sub batch_import { if ( $format eq 'cch-fixed' || $format eq 'cch-fixed-update' ) { $format =~ s/-fixed//; my $date_format = sub { my $r=''; - /^(\d{4})(\d{2})(\d{2})$/ && ($r="$1/$2/$3"); + /^(\d{4})(\d{2})(\d{2})$/ && ($r="$3/$2/$1"); $r; }; my $trim = sub { my $r = shift; $r =~ s/^\s*//; $r =~ s/\s*$//; $r }; @@ -617,7 +619,13 @@ sub batch_import { $hash->{'actionflag'} ='I' if ($hash->{'data_vendor'} eq 'cch'); $hash->{'data_vendor'} ='cch'; - $hash->{'effective_date'} = str2time($hash->{'effective_date'}); + my $parser = new DateTime::Format::Strptime( pattern => "%m/%d/%Y", + time_zone => 'floating', + ); + my $dt = $parser->parse_datetime( $hash->{'effective_date'} ); + $hash->{'effective_date'} = $dt ? $dt->epoch : ''; + + $hash->{$_} = sprintf("%.2f", $hash->{$_}) foreach qw( taxbase taxmax ); my $taxclassid = join(':', map{ $hash->{$_} } qw(taxtype taxcat) ); -- cgit v1.2.1 From e5ed992c003ce75def88da5f40f0ed2096461348 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 18 May 2009 08:40:00 +0000 Subject: it would help to use the correct port, RT#4081 --- FS/bin/freeside-cdr-sftp_and_import | 4 ---- 1 file changed, 4 deletions(-) diff --git a/FS/bin/freeside-cdr-sftp_and_import b/FS/bin/freeside-cdr-sftp_and_import index 5786774d2..c4484f1d4 100755 --- a/FS/bin/freeside-cdr-sftp_and_import +++ b/FS/bin/freeside-cdr-sftp_and_import @@ -92,10 +92,6 @@ sub sftp { my %sftp = ( host => $servername ); - #XXX remove these - $sftp{port} = 10022; - #$sftp{more} = '-v'; - $sftp = Net::SFTP::Foreign->new(%sftp); $sftp->error and die "SFTP connection failed: ". $sftp->error; -- cgit v1.2.1 From aab3bdd971c21f6d422b7708ecf8ba7cb5ec0fea Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 18 May 2009 09:55:30 +0000 Subject: basic CDR viewing from self-service, RT#4018 --- FS/FS/ClientAPI/MyAccount.pm | 128 ++++++++++++++------- FS/FS/UI/bytecount.pm | 7 +- FS/FS/cust_svc.pm | 38 ++++-- fs_selfservice/FS-SelfService/SelfService.pm | 1 + fs_selfservice/FS-SelfService/cgi/header.html | 9 ++ fs_selfservice/FS-SelfService/cgi/selfservice.cgi | 16 ++- .../FS-SelfService/cgi/view_cdr_details.html | 54 +++++++++ fs_selfservice/FS-SelfService/cgi/view_usage.html | 68 +++++++---- 8 files changed, 250 insertions(+), 71 deletions(-) create mode 100644 fs_selfservice/FS-SelfService/cgi/header.html create mode 100644 fs_selfservice/FS-SelfService/cgi/view_cdr_details.html diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index d64c72c0e..ab5096891 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -10,7 +10,7 @@ use Business::CreditCard; use Time::Duration; use FS::UI::Web::small_custview qw(small_custview); #less doh use FS::UI::Web; -use FS::UI::bytecount; +use FS::UI::bytecount qw( display_bytecount ); use FS::Conf; use FS::Record qw(qsearch qsearchs); use FS::Msgcat qw(gettext); @@ -772,8 +772,14 @@ sub list_svcs { : $cust_main->unsuspended_pkgs ) { push @cust_svc, @{[ $cust_pkg->cust_svc ]}; #@{[ ]} to force array context } - @cust_svc = grep { $_->part_svc->svcdb eq $p->{'svcdb'} } @cust_svc - if $p->{'svcdb'}; + if ( $p->{'svcdb'} ) { + my $svcdb = ref($p->{'svcdb'}) eq 'HASH' + ? $p->{'svcdb'} + : ref($p->{'svcdb'}) eq 'ARRAY' + ? { map { $_=>1 } @{ $p->{'svcdb'} } } + : { $p->{'svcdb'} => 1 }; + @cust_svc = grep $svcdb->{ $_->part_svc->svcdb }, @cust_svc + } #@svc_x = sort { $a->domain cmp $b->domain || $a->username cmp $b->username } # @svc_x; @@ -781,30 +787,51 @@ sub list_svcs { { #no#'svcnum' => $session->{'svcnum'}, 'custnum' => $custnum, - 'svcs' => [ map { - my $svc_x = $_->svc_x; - my($label, $value) = $_->label; - my $part_pkg = $svc_x->cust_svc->cust_pkg->part_pkg; - - { 'svcnum' => $_->svcnum, - 'label' => $label, - 'value' => $value, - 'username' => $svc_x->username, - 'email' => $svc_x->email, - 'seconds' => $svc_x->seconds, - 'upbytes' => FS::UI::bytecount::display_bytecount($svc_x->upbytes), - 'downbytes' => FS::UI::bytecount::display_bytecount($svc_x->downbytes), - 'totalbytes'=> FS::UI::bytecount::display_bytecount($svc_x->totalbytes), - 'recharge_amount' => $part_pkg->option('recharge_amount', 1), - 'recharge_seconds' => $part_pkg->option('recharge_seconds', 1), - 'recharge_upbytes' => FS::UI::bytecount::display_bytecount($part_pkg->option('recharge_upbytes', 1)), - 'recharge_downbytes' => FS::UI::bytecount::display_bytecount($part_pkg->option('recharge_downbytes', 1)), - 'recharge_totalbytes' => FS::UI::bytecount::display_bytecount($part_pkg->option('recharge_totalbytes', 1)), - # more... - }; - } - @cust_svc - ], + 'svcs' => [ + map { + my $svc_x = $_->svc_x; + my($label, $value) = $_->label; + my $svcdb = $_->part_svc->svcdb; + my $part_pkg = $_->cust_pkg->part_pkg; + + my %hash = ( + 'svcnum' => $_->svcnum, + 'svcdb' => $svcdb, + 'label' => $label, + 'value' => $value, + ); + + if ( $svcdb eq 'svc_acct' ) { + %hash = ( + %hash, + 'username' => $svc_x->username, + 'email' => $svc_x->email, + 'seconds' => $svc_x->seconds, + 'upbytes' => display_bytecount($svc_x->upbytes), + 'downbytes' => display_bytecount($svc_x->downbytes), + 'totalbytes' => display_bytecount($svc_x->totalbytes), + + 'recharge_amount' => $part_pkg->option('recharge_amount',1), + 'recharge_seconds' => $part_pkg->option('recharge_seconds',1), + 'recharge_upbytes' => + display_bytecount($part_pkg->option('recharge_upbytes',1)), + 'recharge_downbytes' => + display_bytecount($part_pkg->option('recharge_downbytes',1)), + 'recharge_totalbytes' => + display_bytecount($part_pkg->option('recharge_totalbytes',1)), + # more... + ); + + } elsif ( $svcdb eq 'svc_phone' ) { + %hash = ( + %hash, + ); + } + + \%hash; + } + @cust_svc + ], }; } @@ -814,9 +841,8 @@ sub _list_svc_usage { my @usage = (); foreach my $part_export ( map { qsearch ( 'part_export', { 'exporttype' => $_ } ) } - qw (sqlradius sqlradius_withdomain') + qw( sqlradius sqlradius_withdomain ) ) { - push @usage, @ { $part_export->usage_sessions($begin, $end, $svc_acct) }; } (@usage); @@ -849,29 +875,50 @@ sub list_support_usage { _usage_details(\&_list_support_usage, @_); } +sub _list_cdr_usage { + my($svc_phone, $begin, $end) = @_; + map [ $_->downstream_csv('format' => 'default') ], #XXX config for format + $svc_phone->cust_svc->get_cdrs( 'begin'=>$begin, 'end'=>$end, ); +} + +sub list_cdr_usage { + my $p = shift; + _usage_details( \&_list_cdr_usage, $p, + 'svcdb' => 'svc_phone', + ); +} + sub _usage_details { - my ($callback, $p) = (shift,shift); + my($callback, $p, %opt) = @_; my($context, $session, $custnum) = _custoragent_session_custnum($p); return { 'error' => $session } if $context eq 'error'; my $search = { 'svcnum' => $p->{'svcnum'} }; $search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent'; - my $svc_acct = qsearchs ( 'svc_acct', $search ); + + my $svcdb = $opt{'svcdb'} || 'svc_acct'; + + my $svc_x = qsearchs( $svcdb, $search ); return { 'error' => 'No service selected in list_svc_usage' } - unless $svc_acct; + unless $svc_x; - my $freq = $svc_acct->cust_svc->cust_pkg->part_pkg->freq; - my $start = $svc_acct->cust_svc->cust_pkg->setup; - #my $end = $svc_acct->cust_svc->cust_pkg->bill; # or time? - my $end = time; + my $header = $svcdb eq 'svc_phone' + ? [ split(',', FS::cdr::invoice_header('default') ) ] #XXX + : []; - unless($p->{beginning}){ - $p->{beginning} = $svc_acct->cust_svc->cust_pkg->last_bill; - $p->{ending} = $end; + my $cust_pkg = $svc_x->cust_svc->cust_pkg; + my $freq = $cust_pkg->part_pkg->freq; + my $start = $cust_pkg->setup; + #my $end = $cust_pkg->bill; # or time? + my $end = time; + + unless ( $p->{beginning} ) { + $p->{beginning} = $cust_pkg->last_bill; + $p->{ending} = $end; } - my (@usage) = &$callback($svc_acct,$p->{beginning},$p->{ending}); + my (@usage) = &$callback($svc_x, $p->{beginning}, $p->{ending}); #kinda false laziness with FS::cust_main::bill, but perhaps #we should really change this bit to DateTime and DateTime::Duration @@ -914,6 +961,7 @@ sub _usage_details { 'ending' => $p->{ending}, 'previous' => ($previous > $start) ? $previous : $start, 'next' => ($next < $end) ? $next : $end, + 'header' => $header, 'usage' => \@usage, }; } diff --git a/FS/FS/UI/bytecount.pm b/FS/FS/UI/bytecount.pm index 0ddc7545c..7e78bf501 100644 --- a/FS/FS/UI/bytecount.pm +++ b/FS/FS/UI/bytecount.pm @@ -1,10 +1,15 @@ package FS::UI::bytecount; use strict; -use vars qw($DEBUG $me); +use vars qw($DEBUG $me @ISA @EXPORT_OK); +use Exporter; use FS::Conf; use Number::Format 1.50; +@ISA = qw( Exporter ); + +@EXPORT_OK = qw( bytecount_unexact parse_bytecount display_bytecount ); + $DEBUG = 0; $me = '[FS::UID::bytecount]'; diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index c4a75f77a..fe831381f 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -692,32 +692,56 @@ CDRs are associated with svc_phone services via svc_phone.phonenum =cut sub get_cdrs_for_update { + my $self = shift; + $self->get_cdrs( 'freesidestatus' => '', + 'for_update' => 1, + @_, + ); +} + +sub get_cdrs { my($self, %options) = @_; my @fields = ( 'charged_party' ); push @fields, 'src' unless $options{'disable_src'}; - #CDRs are now associated with svc_phone services via svc_phone.phonenum + my $for_update = $options{'for_update'} ? 'FOR UPDATE' : ''; + + my %hash = (); + $hash{'freesidestatus'} = $options{'freesidestatus'} + if exists($options{'freesidestatus'}); + + #CDRs are associated with svc_phone services via svc_phone.phonenum + #return () unless $self->svc_x->isa('FS::svc_phone'); return () unless $self->part_svc->svcdb eq 'svc_phone'; my $number = $self->svc_x->phonenum; my $prefix = $options{'default_prefix'}; - my @where = map " $_ = '$number' ", @fields; - push @where, map " $_ = '$prefix$number' ", @fields + my @orwhere = map " $_ = '$number' ", @fields; + push @orwhere, map " $_ = '$prefix$number' ", @fields if length($prefix); if ( $prefix =~ /^\+(\d+)$/ ) { - push @where, map " $_ = '$1$number' ", @fields + push @orwhere, map " $_ = '$1$number' ", @fields + } + + my @where = ( ' ( '. join(' OR ', @orwhere ). ' ) ' ); + + if ( $options{'begin'} ) { + push @where, 'startdate >= '. $options{'begin'}; + } + if ( $options{'end'} ) { + push @where, 'startdate < '. $options{'end'}; } - my $extra_sql = ' AND ( '. join(' OR ', @where ). ' ) '; + my $extra_sql = ( keys(%hash) ? ' AND ' : ' WHERE ' ). join(' AND ', @where ); my @cdrs = qsearch( { 'table' => 'cdr', - 'hashref' => { 'freesidestatus' => '', }, - 'extra_sql' => "$extra_sql FOR UPDATE", + 'hashref' => \%hash, + 'extra_sql' => "$extra_sql $for_update", } ); @cdrs; diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index fef211580..47f312ac0 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -45,6 +45,7 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'list_pkgs' => 'MyAccount/list_pkgs', #add to ss (added?) 'list_svcs' => 'MyAccount/list_svcs', #add to ss (added?) 'list_svc_usage' => 'MyAccount/list_svc_usage', + 'list_cdr_usage' => 'MyAccount/list_cdr_usage', 'list_support_usage' => 'MyAccount/list_support_usage', 'order_pkg' => 'MyAccount/order_pkg', #add to ss cgi! 'change_pkg' => 'MyAccount/change_pkg', diff --git a/fs_selfservice/FS-SelfService/cgi/header.html b/fs_selfservice/FS-SelfService/cgi/header.html new file mode 100644 index 000000000..cf8fd2bd9 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/header.html @@ -0,0 +1,9 @@ + + + MyAccount + + + MyAccount +

+ <%= include('myaccount_menu') %> + diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index bb3db12c6..ecf2553a3 100644 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -15,7 +15,8 @@ use FS::SelfService qw( login_info login customer_info edit_info invoice list_pkgs order_pkg signup_info order_recharge part_svc_info provision_acct provision_external unprovision_svc change_pkg domainselector - list_svcs list_svc_usage list_support_usage + list_svcs + list_svc_usage list_cdr_usage list_support_usage myaccount_passwd ); @@ -72,7 +73,7 @@ $session_id = $cgi->param('session'); #order|pw_list XXX ??? $cgi->param('action') =~ - /^(myaccount|view_invoice|make_payment|make_ach_payment|make_thirdparty_payment|payment_results|ach_payment_results|recharge_prepay|recharge_results|logout|change_bill|change_ship|change_pay|process_change_bill|process_change_ship|process_change_pay|customer_order_pkg|process_order_pkg|customer_change_pkg|process_change_pkg|process_order_recharge|provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|view_usage|view_usage_details|view_support_details|change_password|process_change_password)$/ + /^(myaccount|view_invoice|make_payment|make_ach_payment|make_thirdparty_payment|payment_results|ach_payment_results|recharge_prepay|recharge_results|logout|change_bill|change_ship|change_pay|process_change_bill|process_change_ship|process_change_pay|customer_order_pkg|process_order_pkg|customer_change_pkg|process_change_pkg|process_order_recharge|provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|view_usage|view_usage_details|view_cdr_details|view_support_details|change_password|process_change_password)$/ or die "unknown action ". $cgi->param('action'); my $action = $1; @@ -564,7 +565,7 @@ sub delete_svc { sub view_usage { list_svcs( 'session_id' => $session_id, - 'svcdb' => 'svc_acct', + 'svcdb' => [ 'svc_acct', 'svc_phone' ], 'ncancelled' => 1, ); } @@ -578,6 +579,15 @@ sub view_usage_details { ); } +sub view_cdr_details { + list_cdr_usage( + 'session_id' => $session_id, + 'svcnum' => $cgi->param('svcnum'), + 'beginning' => $cgi->param('beginning') || '', + 'ending' => $cgi->param('ending') || '', + ); +} + sub view_support_details { list_support_usage( 'session_id' => $session_id, diff --git a/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html b/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html new file mode 100644 index 000000000..32bd632b4 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/view_cdr_details.html @@ -0,0 +1,54 @@ +<%= $url = "$selfurl?session=$session_id;action="; ''; %> +<%= include('header') %> + +Call usage for +<%= Date::Format::time2str('%b %o %Y', $beginning) %> - +<%= Date::Format::time2str('%b %o %Y', $ending) %> +

+ +<%= if ( $error ) { + $OUT .= qq!$error

!; +} ''; %> + + + + + + +
+<%= if ($previous < $beginning) { + $OUT .= qq!Previous period!; + }else{ + ''; + } %> + +<%= if ($next > $ending) { + $OUT .= qq!Next period!; + }else{ + ''; + }%> +
+ + +<%= foreach my $header (@header) { + $OUT .= qq(); + } +%> + +<%= my $total = 0; + my $utotal = 0; + my $dtotal = 0; + foreach my $usage ( @usage ) { + $OUT .= ''; + $OUT .= qq() foreach @{$usage}; + $OUT .= ''; + } +%> + +
$header
$_
+
+ + +<%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/view_usage.html b/fs_selfservice/FS-SelfService/cgi/view_usage.html index b78f9975b..b492102ce 100644 --- a/fs_selfservice/FS-SelfService/cgi/view_usage.html +++ b/fs_selfservice/FS-SelfService/cgi/view_usage.html @@ -1,24 +1,30 @@ -MyAccount -MyAccount

-<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - - -Service usage

+<%= $url = "$selfurl?session=$session_id;action="; + @svc_acct = grep { $_->{svcdb} eq 'svc_acct' } @svcs; + @svc_phone = grep { $_->{svcdb} eq 'svc_phone' } @svcs; + ''; +%> +<%= include('header') %> <%= if ( $error ) { $OUT .= qq!$error

!; } ''; %> - - - - - - - - -<%= foreach my $svc ( @svcs ) { +<%= if ( @svc_acct ) { + $OUT.= 'Account usage

+
AccountTime remainingUpload remainingDownload remainingTotal remaining
+ + + + + + + '; + } else { + $OUT .= ''; + } +%> + +<%= foreach my $svc ( @svc_acct ) { my $link = "${url}view_usage_details;". "svcnum=$svc->{'svcnum'};beginning=0;ending=0"; $OUT .= ''; } - } %> + } +%> -
AccountTime remainingUpload remainingDownload remainingTotal remaining
'; @@ -48,11 +54,33 @@ $OUT .= $svc->{'recharge_totalbytes'} if $svc->{'recharge_totalbytes'}; $OUT .= '
-
+<%= scalar(@svc_acct) ? '

' : '' %> - +<%= if ( @svc_phone ) { + $OUT.= 'Call usage

+ + + '; #"Account" ? + #what else? + $OUT .= ''; + } else { + $OUT .= ''; + } +%> +<%= foreach my $svc_phone ( @svc_phone ) { + my $link = "${url}view_cdr_details;". + "svcnum=$svc_phone->{'svcnum'};beginning=0;ending=0"; + $OUT .= ''; + } +%> + +<%= scalar(@svc_phone) ? '
Number
'; + $OUT .= qq!!. $svc_phone->{'label'}. ': '. $svc_phone->{'value'}.''; + $OUT .= '


' : '' %> + + <%= include('footer') %> -- cgit v1.2.1 From c6ba0fa6271880599ce3d60dcd23de248526f0b8 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 18 May 2009 18:21:38 +0000 Subject: prevent death on meritless sqlradius upgrade attempts --- FS/bin/freeside-upgrade | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/FS/bin/freeside-upgrade b/FS/bin/freeside-upgrade index 24f577f11..7ee35c68d 100755 --- a/FS/bin/freeside-upgrade +++ b/FS/bin/freeside-upgrade @@ -1,7 +1,7 @@ #!/usr/bin/perl -w use strict; -use vars qw($opt_d $opt_s $opt_q $opt_v); +use vars qw($opt_d $opt_s $opt_q $opt_v $opt_r); use vars qw($DEBUG $DRY_RUN); use Getopt::Std; use DBIx::DBSchema 0.31; @@ -17,7 +17,7 @@ my $start = time; die "Not running uid freeside!" unless checkeuid(); -getopts("dqs"); +getopts("dqrs"); $DEBUG = !$opt_q; #$DEBUG = $opt_v; @@ -153,7 +153,7 @@ warn "Table updates completed in ". (time-$start). " seconds\n"; # if $DEBUG; $start = time; upgrade_sqlradius() - unless $DRY_RUN || $opt_s; + unless $DRY_RUN || $opt_s || $opt_r; warn "SQL RADIUS updates completed in ". (time-$start). " seconds\n"; # if $DEBUG; $start = time; @@ -172,7 +172,7 @@ sub dbdef_create { # reverse engineer the schema from the DB and save to file } sub usage { - die "Usage:\n freeside-upgrade [ -d ] [ -s ] [ -q | -v ] user\n"; + die "Usage:\n freeside-upgrade [ -d ] [ -r ] [ -s ] [ -q | -v ] user\n"; } =head1 NAME @@ -181,7 +181,7 @@ freeside-upgrade - Upgrades database schema for new freeside verisons. =head1 SYNOPSIS - freeside-upgrade [ -d ] [ -s ] [ -q | -v ] + freeside-upgrade [ -d ] [ -r ] [ -s ] [ -q | -v ] =head1 DESCRIPTION @@ -203,6 +203,9 @@ Also performs other upgrade functions: [ -q ]: Run quietly. This may become the default at some point. + [ -r ]: Skip sqlradius updates. Useful for occassions where the sqlradius + databases may be inaccessible. + [ -v ]: Run verbosely, sending debugging information to STDERR. This is the current default. -- cgit v1.2.1 From c866a1f8480b05f87230579a19c9e0fe0a5e7ac1 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 18 May 2009 19:21:36 +0000 Subject: allow empty state --- FS/FS/Schema.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index a9b546940..e9861f8d1 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -827,7 +827,7 @@ sub tables_hashref { 'geocode', 'varchar', '', 20, '', '', 'city', 'varchar', 'NULL', $char_d, '', '', 'county', 'varchar', 'NULL', $char_d, '', '', - 'state', 'char', '', 2, '', '', + 'state', 'char', 'NULL', 2, '', '', 'disabled', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'taxratelocationnum', -- cgit v1.2.1 From b3f5d82f666ad38799cae84f0b50bad2b0450d40 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 18 May 2009 19:23:27 +0000 Subject: miss use --- FS/FS/tax_rate_location.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/tax_rate_location.pm b/FS/FS/tax_rate_location.pm index 65bef7bf7..0e0dafebb 100644 --- a/FS/FS/tax_rate_location.pm +++ b/FS/FS/tax_rate_location.pm @@ -3,6 +3,7 @@ package FS::tax_rate_location; use strict; use base qw( FS::Record ); use FS::Record qw( qsearch qsearchs dbh ); +use FS::Misc qw( csv_from_fixed ); =head1 NAME -- cgit v1.2.1 From 2b968bffd937b19d2314aa5e304fccc8ec1e1350 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 20 May 2009 01:06:41 +0000 Subject: first pass at netsapiens integration, RT#5226 --- FS/FS/part_export/netsapiens.pm | 198 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 FS/FS/part_export/netsapiens.pm diff --git a/FS/FS/part_export/netsapiens.pm b/FS/FS/part_export/netsapiens.pm new file mode 100644 index 000000000..10b53ef51 --- /dev/null +++ b/FS/FS/part_export/netsapiens.pm @@ -0,0 +1,198 @@ +package FS::part_export::netsapiens; + +use vars qw(@ISA %info); +use URI; +use MIME::Base64; +use Tie::IxHash; +use FS::part_export; + +@ISA = qw(FS::part_export); + +tie my %options, 'Tie::IxHash', + 'login' => { label=>'NetSapiens tac2 API username' }, + 'password' => { label=>'NetSapiens tac2 API password' }, + 'url' => { label=>'NetSapiens tac2 URL' }, + 'domain' => { label=>'NetSapiens Domain' }, +; + +%info = ( + 'svc' => 'svc_phone', + 'desc' => 'Provision phone numbers to NetSapiens', + 'options' => \%options, + 'notes' => <<'END' +Requires installation of +REST::Client +from CPAN. +END +); + +sub rebless { shift; } + +sub ns_command { + my( $self, $method, $command, @args ) = @_; + + eval 'use REST::Client'; + die $@ if $@; + + my $ns = new REST::Client 'host'=>$self->option('url'); + + my $content = $method eq 'PUT' ? $ns->buildQuery( { @args } ) : ''; + $content =~ s/^\?//; + + warn $content; + + my $auth = + encode_base64( $self->option('login'). ':'. $self->option('password') ); + + $ns->$method( $command, $content, { 'Authorization' => "Basic $auth" } ); + + $ns; +} + +sub ns_subscriber { + my($self, $svc_phone) = (shift, shift); + + my $domain = $self->option('domain'); + my $phonenum = $svc_phone->phonenum; + + "/domains_config/$domain/subscriber_config/$phonenum"; +} + +sub ns_create_or_update { + my($self, $svc_phone, $dial_policy) = (shift, shift, shift); + + my $domain = $self->option('domain'); + my $phonenum = $svc_phone->phonenum; + + my( $firstname, $lastname ); + if ( $svc_phone->phone_name =~ /^\s*(\S+)\s+(\S.*\S)\s*$/ ) { + $firstname = $1; + $lastname = $2; + } else { + #deal w/unaudited netsapiens services? + my $cust_main = $svc_phone->cust_svc->cust_pkg->cust_main; + $firstname = $cust_main->get('first'); + $lastname = $cust_main->get('last'); + } + + my $ns = $self->ns_command( 'PUT', $self->ns_subscriber($svc_phone), + 'subscriber_login' => $phonenum.'@'.$domain, + 'firstname' => $firstname, #4? + 'lastname' => $lastname, #5? + 'subscriber_pin' => $svc_phone->pin, #6? + 'dial_plan' => 'Default', #config? #7? + 'dial_policy' => $dial_policy, #8? +#no_answer_timeout30 +# simultaneous_ringyes +# gmt_offset-8 +# aor_schemesip: +# do_not_disturbyes +# email_vmail +# data_limit0 +# screen +# last_update2008-10-01 12:19:01.0 +# domain_diryes +# callid_name[*] +# admin_vmailyes +# subscriber_name +# rcv_broadcast +# directory_order1 +# accept +# rating_required +# date_created2008-02-22 08:38:01 +# message_waiting +# rate +# directory_listingno +# time_zoneUS/Pacific +# forward_no_answeryes +# vmail_sort_lifo +# modeover-capacity +# subscriber_groupn/a +# vmail_say_time +# presenceinactive +# directory_match826 +# language +# forward_busyyes +# callid_nmbr[*] +# vmail +# subscriber_login1007@vbox.netsapiens.com +# rejectyes +# forwardyes +# vmail_say_cidno +# email_address +# greeting_index + ); + + if ( $ns->responseCode !~ /^2/ ) { + return $ns->responseCode. ' '. + join(', ', $self->ns_parse_response( $ns->responseContent ) ); + } + + ''; +} + +sub ns_delete { + my($self, $svc_phone) = (shift, shift); + + my $ns = $self->ns_command( 'DELETE', $self->ns_subscriber($svc_phone) ); + + if ( $ns->responseCode !~ /^2/ ) { + return $ns->responseCode. ' '. + join(', ', $self->ns_parse_response( $ns->responseContent ) ); + } + + ''; + +} + +sub ns_parse_response { + my( $self, $content ) = ( shift, shift ); + + tie my %hash, Tie::IxHash; + #while ( $content =~ s/^.*?

\s*(.+?)<\/b>\s*<(\w+)>(.+?)<\/\2><\/p>//i ) { + while ( $content =~ s/^.*?

\s*(.+?)<\/b>\s*(.+?)\s*<\/p>//is ) { + ( $hash{$1} = $2 ) =~ s/^\s*<(\w+)>(.+?)<\/\1>/$2/is; + } + + #warn $content; #probably useless + + %hash; +} + +sub _export_insert { + my($self, $svc_phone) = (shift, shift); + $self->ns_create_or_update($svc_phone, 'Permit All'); +} + +sub _export_replace { + my( $self, $new, $old ) = (shift, shift, shift); + return "can't change phonenum with NetSapiens (unprovision and reprovision?)" + if $old->phonenum ne $new->phonenum; + $self->_export_insert($new); +} + +sub _export_delete { + my( $self, $svc_phone ) = (shift, shift); + + $self->ns_delete($svc_phone); +} + +sub _export_suspend { + my( $self, $svc_phone ) = (shift, shift); + $self->ns_create_or_udpate($svc_phone, 'Deny'); +} + +sub _export_unsuspend { + my( $self, $svc_phone ) = (shift, shift); + #$self->ns_create_or_update($svc_phone, 'Permit All'); + $self->_export_insert($svc_phone); +} + +sub export_links { + my($self, $svc_phone, $arrayref) = (shift, shift, shift); + #push @$arrayref, qq!!. $svc_phone->username. qq!!; + ''; +} + +1; -- cgit v1.2.1 From 2fd929f5185673c55f46cca2e8c846c47e7cf959 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 20 May 2009 08:27:39 +0000 Subject: get subscriber deletion working and remove devel cruft, RT#5226 --- FS/FS/part_export/netsapiens.pm | 68 +++++++++-------------------------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/FS/FS/part_export/netsapiens.pm b/FS/FS/part_export/netsapiens.pm index 10b53ef51..e19e95cb4 100644 --- a/FS/FS/part_export/netsapiens.pm +++ b/FS/FS/part_export/netsapiens.pm @@ -29,23 +29,26 @@ END sub rebless { shift; } sub ns_command { - my( $self, $method, $command, @args ) = @_; + my( $self, $method, $command ) = splice(@_,0,3); eval 'use REST::Client'; die $@ if $@; my $ns = new REST::Client 'host'=>$self->option('url'); - my $content = $method eq 'PUT' ? $ns->buildQuery( { @args } ) : ''; - $content =~ s/^\?//; + my @args = ( $command ); - warn $content; + if ( $method eq 'PUT' ) { + my $content = $method eq 'PUT' ? $ns->buildQuery( { @_ } ) : ''; + $content =~ s/^\?//; + push @args, $content; + } my $auth = encode_base64( $self->option('login'). ':'. $self->option('password') ); + push @args, { 'Authorization' => "Basic $auth" }; - $ns->$method( $command, $content, { 'Authorization' => "Basic $auth" } ); - + $ns->$method( @args ); $ns; } @@ -77,50 +80,11 @@ sub ns_create_or_update { my $ns = $self->ns_command( 'PUT', $self->ns_subscriber($svc_phone), 'subscriber_login' => $phonenum.'@'.$domain, - 'firstname' => $firstname, #4? - 'lastname' => $lastname, #5? - 'subscriber_pin' => $svc_phone->pin, #6? - 'dial_plan' => 'Default', #config? #7? - 'dial_policy' => $dial_policy, #8? -#no_answer_timeout30 -# simultaneous_ringyes -# gmt_offset-8 -# aor_schemesip: -# do_not_disturbyes -# email_vmail -# data_limit0 -# screen -# last_update2008-10-01 12:19:01.0 -# domain_diryes -# callid_name[*] -# admin_vmailyes -# subscriber_name -# rcv_broadcast -# directory_order1 -# accept -# rating_required -# date_created2008-02-22 08:38:01 -# message_waiting -# rate -# directory_listingno -# time_zoneUS/Pacific -# forward_no_answeryes -# vmail_sort_lifo -# modeover-capacity -# subscriber_groupn/a -# vmail_say_time -# presenceinactive -# directory_match826 -# language -# forward_busyyes -# callid_nmbr[*] -# vmail -# subscriber_login1007@vbox.netsapiens.com -# rejectyes -# forwardyes -# vmail_say_cidno -# email_address -# greeting_index + 'firstname' => $firstname, + 'lastname' => $lastname, + 'subscriber_pin' => $svc_phone->pin, + 'dial_plan' => 'Default', #config? + 'dial_policy' => $dial_policy, ); if ( $ns->responseCode !~ /^2/ ) { @@ -148,14 +112,12 @@ sub ns_delete { sub ns_parse_response { my( $self, $content ) = ( shift, shift ); + #try to screen-scrape something useful tie my %hash, Tie::IxHash; - #while ( $content =~ s/^.*?

\s*(.+?)<\/b>\s*<(\w+)>(.+?)<\/\2><\/p>//i ) { while ( $content =~ s/^.*?

+while ( $content =~ + s/^.*?//is ) +{ + + my $accountcode = $1; + warn "$accountcode\n" if $DEBUG; + + $content =~ s/(.*?)<\/form>//is; + my $cdr_content = $1; + + while ( $cdr_content =~ + s/.*?//is ) + { + warn " $1 => $2\n" if $DEBUG > 1; + + my $cdr = new FS::cdr { + #'src' => + #'dst' => +# 'startdate' => 'time_start', #XXX needs parsing +# 'enddate' => 'time_release', #XXX needs parsing + 'duration' => 'duration', + 'billsec' => 'time_talking', + #'disposition' => + 'accountcode' => $accountcode, + #'charged_party' + }; + + + } + +} + +sub usage { + "Usage: \n cdr-netsapiens.import user exportnum\n"; +} + +__END__ + + rly_prt_0 => 23946 + orig_req_host => residential.skynet360.com + batch_dura => 0 + orig_from_host => 63.251.149.5 + batch_tim_beg => 2009-02-19 20:17:19 + term_match => sip:7865457300@residential.skynet360.com + term_domain => residential.skynet360.com + term_sub => 7865457300 + orig_req_user => 7865457300 + orig_callid => 5D1164E6-44E011D6-8C84C368-EA5A0BC4@63.251.149.5 + term_ip => 63.251.148.137:1453 + term_to_uri => sip:7865457300@residential.skynet360.com + release_code => end + time_start => 2009-02-19 20:17:19.0 + batch_hold => 0 + orig_from_user => 9046384544 + time_holding => 0 + term_logi_uri => sip:7865457300@residential.skynet360.com + time_talking => 0 + orig_from_uri => sip:9046384544@63.251.149.5 + duration => 0 + orig_logi_uri => sip:9046384544@63.251.149.5 + rly_cnt_b => 0 + time_insert => 2009-02-19 15:17:38.0 + orig_to_user => 7865457300 + rly_prt_a => 63.251.149.18:21972 + cdr_index => 0 + orig_to_host => 63.251.149.18 + orig_match => sip:*@63.251.149.5 + time_release => 2009-02-19 20:17:37 + codec => G.711 u-law + orig_req_uri => sip:7865457300@residential.skynet360.com + orig_to_uri => sip:7865457300@63.251.149.18 + rly_cnt_a => 13 + orig_ip => 63.251.149.5:57326 + release_text => Orig: Cancel + time_disp => 0 + time_ringing => 2009-02-19 20:17:19 + _method => put +prt_0 => 23946 + orig_req_host => residential.skynet360.com + batch_dura => 0 + orig_from_host => 63.251.149.5 + batch_tim_beg => 2009-02-19 20:17:19 + term_match => sip:7865457300@residential.skynet360.com + term_domain => residential.skynet360.com + time_start => 2009-02-19 20:17:19.0 + term_sub => 7865457300 + orig_req_user => 7865457300 + orig_callid => 5D1164E6-44E011D6-8C84C368-EA5A0BC4@63.251.149.5 + term_ip => 63.251.148.137:1453 + term_to_uri => sip:7865457300@residential.skynet360.com + release_code => end + time_start => 2009-02-19 20:17:19.0 + batch_hold => 0 + orig_from_user => 9046384544 + time_holding => 0 + term_logi_uri => sip:7865457300@residential.skynet360.com + time_talking => 0 + orig_from_uri => sip:9046384544@63.251.149.5 + duration => 0 + orig_logi_uri => sip:9046384544@63.251.149.5 + rly_cnt_b => 0 + time_insert => 2009-02-19 15:17:38.0 + orig_to_user => 7865457300 + rly_prt_a => 63.251.149.18:21972 + cdr_index => 0 + orig_to_host => 63.251.149.18 + orig_match => sip:*@63.251.149.5 + time_release => 2009-02-19 20:17:37 + codec => G.711 u-law + orig_req_uri => sip:7865457300@residential.skynet360.com + orig_to_uri => sip:7865457300@63.251.149.18 + rly_cnt_a => 13 + orig_ip => 63.251.149.5:57326 + release_text => Orig: Cancel + time_disp => 0 + time_ringing => 2009-02-19 20:17:19 + _method => put + +list of freeside CDR fields, useful ones marked with * + + acctid - primary key +*[1] calldate - Call timestamp (SQL timestamp) + clid - Caller*ID with text +* src - Caller*ID number / Source number +* dst - Destination extension + dcontext - Destination context + channel - Channel used + dstchannel - Destination channel if appropriate + lastapp - Last application if appropriate + lastdata - Last application data +* startdate - Start of call (UNIX-style integer timestamp) + answerdate - Answer time of call (UNIX-style integer timestamp) +* enddate - End time of call (UNIX-style integer timestamp) +* duration - Total time in system, in seconds +* billsec - Total time call is up, in seconds +*[2] disposition - What happened to the call: ANSWERED, NO ANSWER, BUSY + amaflags - What flags to use: BILL, IGNORE etc, specified on a per + channel basis like accountcode. +*[3] accountcode - CDR account number to use: account + uniqueid - Unique channel identifier (Unitel/RSLCOM Event ID) + userfield - CDR user-defined field + cdr_type - CDR type - see FS::cdr_type (Usage = 1, S&E = 7, OC&C = 8) +*[4] charged_party - Service number to be billed + upstream_currency - Wholesale currency from upstream +*[5] upstream_price - Wholesale price from upstream + upstream_rateplanid - Upstream rate plan ID + rated_price - Rated (or re-rated) price + distance - km (need units field?) + islocal - Local - 1, Non Local = 0 +*[6] calltypenum - Type of call - see FS::cdr_calltype + description - Description (cdr_type 7&8 only) (used for + cust_bill_pkg.itemdesc) + quantity - Number of items (cdr_type 7&8 only) + carrierid - Upstream Carrier ID (see FS::cdr_carrier) + upstream_rateid - Upstream Rate ID + svcnum - Link to customer service (see FS::cust_svc) + freesidestatus - NULL, done (or something) + +[1] Auto-populated from startdate if not present +[2] Package options available to ignore calls without a specific disposition +[3] When using 'cdr-charged_party-accountcode' config +[4] Auto-populated from src (normal calls) or dst (toll free calls) if not present +[5] When using 'upstream_simple' rating method. +[6] Set to usage class classnum when using pre-rated CDRs and usage class-based + taxation (local/intrastate/interstate/international) + + -- cgit v1.2.1 From 9832f4d4086970d7612ff2a6facd797fa85d7814 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 31 May 2009 06:59:37 +0000 Subject: package definition browse/search, filter by package class, RT#5255 --- httemplate/browse/part_pkg.cgi | 61 +++++++++++++++++++++++++++-------- httemplate/elements/select-table.html | 9 ++++-- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi index 26028b6ad..886c6c849 100755 --- a/httemplate/browse/part_pkg.cgi +++ b/httemplate/browse/part_pkg.cgi @@ -1,6 +1,7 @@ <% include( 'elements/browse.html', 'title' => 'Package Definitions', 'html_init' => $html_init, + 'html_posttotal' => $html_posttotal, 'name' => 'package definitions', 'disableable' => 1, 'disabled_statuspos' => 3, @@ -48,10 +49,10 @@ if ( $cgi->param('active') ) { $orderby = 'num_active DESC'; } -my $extra_sql = ''; +my @where = (); #if ( $cgi->param('activeONLY') ) { -# $extra_sql = ' WHERE num_active > 0 '; #XXX doesn't affect count... +# push @where, ' WHERE num_active > 0 '; #XXX doesn't affect count... #} if ( $cgi->param('recurring') ) { @@ -59,21 +60,30 @@ if ( $cgi->param('recurring') ) { $extra_count = ' freq != 0 '; } -if ( $cgi->param('missing_recur_fee') ) { - my $missing = "0 = ( SELECT COUNT(*) FROM part_pkg_option - WHERE optionname = 'recur_fee' - AND part_pkg_option.pkgpart = part_pkg.pkgpart - AND CAST ( optionvalue AS NUMERIC ) > 0 - )"; - $extra_sql .= ( ( scalar(keys %hash) || $extra_sql ) ? ' AND ' : ' WHERE ' ). - $missing; +my $classnum = ''; +if ( $cgi->param('classnum') =~ /^(\d+)$/ ) { + $classnum = $1; + push @where, $classnum ? "classnum = $classnum" + : "classnum IS NULL"; } +$cgi->delete('classnum'); -unless ( $acl_edit_global ) { - $extra_sql .= ( ( scalar(keys %hash) || $extra_sql ) ? ' AND ' : ' WHERE ' ). - FS::part_pkg->curuser_pkgs_sql; +if ( $cgi->param('missing_recur_fee') ) { + push @where, "0 = ( SELECT COUNT(*) FROM part_pkg_option + WHERE optionname = 'recur_fee' + AND part_pkg_option.pkgpart = part_pkg.pkgpart + AND CAST ( optionvalue AS NUMERIC ) > 0 + )"; } +push @where, FS::part_pkg->curuser_pkgs_sql + unless $acl_edit_global; + +my $extra_sql = scalar(@where) + ? ( scalar(keys %hash) ? ' AND ' : ' WHERE ' ). + join( 'AND ', @where) + : ''; + my $agentnums = join(',', $curuser->agentnums); my $count_cust_pkg = " SELECT COUNT(*) FROM cust_pkg LEFT JOIN cust_main USING ( custnum ) @@ -117,6 +127,31 @@ my $html_init; !; #} +$cgi->param('dummy', 1); + +my $filter_change = + qq(\n\n"; + +#restore this so pagination works +$cgi->param('classnum', $classnum) if length($classnum); + +my $html_posttotal = + "$filter_change\n
( show class: ". + include('/elements/select-pkg_class.html', + #'curr_value' => $classnum, + 'value' => $classnum, #insist on 0 :/ + 'onchange' => 'filter_change()', + 'pre_options' => [ '-1' => 'all', + '0' => '(none)', ], + 'disable_empty' => 1, + ). + ' )'; + # ------ my $link = [ $p.'edit/part_pkg.cgi?', 'pkgpart' ]; diff --git a/httemplate/elements/select-table.html b/httemplate/elements/select-table.html index e7baaf53b..1a440f07e 100644 --- a/httemplate/elements/select-table.html +++ b/httemplate/elements/select-table.html @@ -64,8 +64,13 @@ Example: > % while ( @pre_options ) { -

\s*(.+?)<\/b>\s*(.+?)\s*<\/p>//is ) { ( $hash{$1} = $2 ) =~ s/^\s*<(\w+)>(.+?)<\/\1>/$2/is; } - #warn $content; #probably useless - %hash; } -- cgit v1.2.1 From 98901e4ef499dfb983bbd0d467eca3a0534bc3e9 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 20 May 2009 15:27:17 +0000 Subject: add "manage device" link & config, RT#5438 --- FS/FS/Conf.pm | 7 +++++++ httemplate/view/cust_main/packages.html | 1 + httemplate/view/cust_main/packages/services.html | 23 +++++++++++++++++------ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index e86ed0d15..87e8517de 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2795,6 +2795,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'svc_broadband-manage_link', + 'section' => 'UI', + 'description' => 'URL for svc_broadband "Manage Device" link. The following substitutions are available: $ip_addr.', + 'type' => 'text', + }, + ); 1; diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index ed98ba903..0c0526d42 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -148,6 +148,7 @@ my %conf_opt = ( #for services.html 'svc_external-skip_manual' => $conf->exists('svc_external-skip_manual'), 'legacy_link' => $conf->exists('legacy_link'), + 'svc_broadband-manage_link' => $conf->config('svc_broadband-manage_link'), ); #subroutines diff --git a/httemplate/view/cust_main/packages/services.html b/httemplate/view/cust_main/packages/services.html index 1e473736b..37cd615eb 100644 --- a/httemplate/view/cust_main/packages/services.html +++ b/httemplate/view/cust_main/packages/services.html @@ -36,15 +36,24 @@ % ) % ) { ( <%svc_recharge_link($cust_svc)%> ) -% } +% } - + -% if ( $curuser->access_right('Unprovision customer service') ) { - ( <%svc_unprovision_link($cust_svc)%> ) -% } - +% my $manage_link = $opt{'svc_broadband-manage_link'}; +% if ( $manage_link && $part_svc->svcdb eq 'svc_broadband' ) { +% my $ip_addr = $cust_svc->svc_x->ip_addr; +% my $svc_manage_link = eval(qq("$manage_link")); + Manage Device ) + +% } + + +% if ( $curuser->access_right('Unprovision customer service') ) { + ( <%svc_unprovision_link($cust_svc)%> ) +% } + % } @@ -75,6 +84,8 @@ my $cust_pkg = $opt{'cust_pkg'}; my $part_pkg = $opt{'part_pkg'}; my $curuser = $FS::CurrentUser::CurrentUser; +my $conf = new FS::Conf; + sub svc_provision_link { my ($cust_pkg, $part_svc, $opt, $curuser) = @_; ( my $svc_nbsp = $part_svc->svc ) =~ s/\s+/ /g; -- cgit v1.2.1 From 0d8c19f122f9f7331aa707192f3bffa473f069a5 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 22 May 2009 03:02:54 +0000 Subject: add ability to report on packages w/status "not yet billed" as well, RT#5409 --- FS/FS/cust_pkg.pm | 30 ++++++++++++++++++++++-------- httemplate/search/report_cust_pkg.html | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 25899364e..93aec6d38 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1683,8 +1683,8 @@ tie my %statuscolor, 'Tie::IxHash', sub statuses { my $self = shift; #could be class... - grep { $_ !~ /^(not yet billed)$/ } #this is a dumb status anyway - # mayble split btw one-time vs. recur + #grep { $_ !~ /^(not yet billed)$/ } #this is a dumb status anyway + # # mayble split btw one-time vs. recur keys %statuscolor; } @@ -2087,6 +2087,18 @@ sub active_sql { " AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 ) "; } +=item not_yet_billed_sql + +Returns an SQL expression identifying packages which have not yet been billed. + +=cut + +sub not_yet_billed_sql { " + ( cust_pkg.setup IS NULL OR cust_pkg.setup = 0 ) + AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 ) + AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 ) +"; } + =item inactive_sql Returns an SQL expression identifying inactive packages (one-time packages @@ -2096,6 +2108,7 @@ that are otherwise unsuspended/uncancelled). sub inactive_sql { " ". $_[0]->onetime_sql(). " + AND cust_pkg.setup IS NOT NULL AND cust_pkg.setup != 0 AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 ) AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 ) "; } @@ -2220,8 +2233,13 @@ sub search_sql { push @where, FS::cust_pkg->active_sql(); - } elsif ( $params->{'magic'} eq 'inactive' - || $params->{'status'} eq 'inactive' ) { + } elsif ( $params->{'magic'} eq 'not yet billed' + || $params->{'status'} eq 'not yet billed' ) { + + push @where, FS::cust_pkg->not_yet_billed_sql(); + + } elsif ( $params->{'magic'} =~ /^(one-time charge|inactive)/ + || $params->{'status'} =~ /^(one-time charge|inactive)/ ) { push @where, FS::cust_pkg->inactive_sql(); @@ -2235,10 +2253,6 @@ sub search_sql { push @where, FS::cust_pkg->cancelled_sql(); - } elsif ( $params->{'status'} =~ /^(one-time charge|inactive)$/ ) { - - push @where, FS::cust_pkg->inactive_sql(); - } ### diff --git a/httemplate/search/report_cust_pkg.html b/httemplate/search/report_cust_pkg.html index aef1c24e5..b5d2d8b79 100755 --- a/httemplate/search/report_cust_pkg.html +++ b/httemplate/search/report_cust_pkg.html @@ -129,6 +129,7 @@ my %label = ( #false laziness w/cust_pkg.cgi my %disable = ( 'all' => {}, + 'not yet billed' => { 'setup'=>1, 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, 'active' => { 'susp'=>1, 'cancel'=>1 }, 'suspended' => { 'cancel' => 1 }, -- cgit v1.2.1 From aa6c509c76c647d05d7bc94ca58effa845cac245 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 22 May 2009 03:22:38 +0000 Subject: commit before sqlradius upgrade so sqlradius upgrade errors from permissions can be ignored for now --- FS/bin/freeside-upgrade | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/FS/bin/freeside-upgrade b/FS/bin/freeside-upgrade index 7ee35c68d..97babbd68 100755 --- a/FS/bin/freeside-upgrade +++ b/FS/bin/freeside-upgrade @@ -149,6 +149,8 @@ $start = time; upgrade() unless $DRY_RUN || $opt_s; +$dbh->commit or die $dbh->errstr; + warn "Table updates completed in ". (time-$start). " seconds\n"; # if $DEBUG; $start = time; @@ -161,7 +163,7 @@ $start = time; $dbh->commit or die $dbh->errstr; $dbh->disconnect or die $dbh->errstr; -warn "Commit and disconnection completed in ". (time-$start). " seconds; upgrade done!\n"; # if $DEBUG; +warn "Final commit and disconnection completed in ". (time-$start). " seconds; upgrade done!\n"; # if $DEBUG; ### -- cgit v1.2.1 From d6b6f81e383f9d876e67e9704914e887a331012e Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 25 May 2009 01:49:34 +0000 Subject: international self-service payments, RT#1592 --- FS/FS/ClientAPI/MasonComponent.pm | 44 ++++++++++++++++- FS/FS/ClientAPI/MyAccount.pm | 7 +-- fs_selfservice/FS-SelfService/SelfService.pm | 55 +++++++++++++++++++++- fs_selfservice/FS-SelfService/cgi/card.html | 50 +++++--------------- .../FS-SelfService/cgi/make_payment.html | 16 +++---- .../FS-SelfService/cgi/misc/counties.cgi | 18 +++++++ fs_selfservice/FS-SelfService/cgi/misc/states.cgi | 18 +++++++ fs_selfservice/FS-SelfService/cgi/selfservice.cgi | 2 +- httemplate/elements/location.html | 20 ++++---- httemplate/elements/select-county.html | 6 ++- 10 files changed, 169 insertions(+), 67 deletions(-) create mode 100755 fs_selfservice/FS-SelfService/cgi/misc/counties.cgi create mode 100755 fs_selfservice/FS-SelfService/cgi/misc/states.cgi diff --git a/FS/FS/ClientAPI/MasonComponent.pm b/FS/FS/ClientAPI/MasonComponent.pm index 78ea9bd4f..d158ce842 100644 --- a/FS/FS/ClientAPI/MasonComponent.pm +++ b/FS/FS/ClientAPI/MasonComponent.pm @@ -1,9 +1,13 @@ package FS::ClientAPI::MasonComponent; use strict; -use vars qw($DEBUG $me); +use vars qw( $cache $DEBUG $me ); +use subs qw( _cache ); use FS::Mason qw( mason_interps ); use FS::Conf; +use FS::ClientAPI_SessionCache; +use FS::Record qw(qsearchs); +use FS::cust_main; $DEBUG = 0; $me = '[FS::ClientAPI::MasonComponent]'; @@ -13,6 +17,24 @@ my %allowed_comps = map { $_=>1 } qw( /misc/areacodes.cgi /misc/exchanges.cgi /misc/phonenums.cgi + /misc/states.cgi + /misc/counties.cgi +); + +my %session_comps = map { $_=>1 } qw( + /elements/location.html +); + +my %session_callbacks = ( + '/elements/location.html' => sub { + my( $custnum, $argsref ) = @_; + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or return "unknown custnum $custnum"; + my %args = @$argsref; + $args{object} = $cust_main; + @$argsref = ( %args ); + return ''; #no error + }, ); my $outbuf; @@ -24,12 +46,23 @@ sub mason_comp { warn "$me mason_comp called on $packet\n" if $DEBUG; my $comp = $packet->{'comp'}; - unless ( $allowed_comps{$comp} ) { + unless ( $allowed_comps{$comp} || $session_comps{$comp} ) { return { 'error' => 'Illegal component' }; } my @args = $packet->{'args'} ? @{ $packet->{'args'} } : (); + if ( $session_comps{$comp} ) { + + my $session = _cache->get($packet->{'session_id'}) + or return ( 'error' => "Can't resume session" ); #better error message + my $custnum = $session->{'custnum'}; + + my $error = &{ $session_callbacks{$comp} }( $custnum, \@args ); + return { 'error' => $error } if $error; + + } + my $conf = new FS::Conf; $FS::Mason::Request::FSURL = $conf->config('selfservice_server-base_url'); $FS::Mason::Request::QUERY_STRING = $packet->{'query_string'} || ''; @@ -43,4 +76,11 @@ sub mason_comp { } +#hmm +sub _cache { + $cache ||= new FS::ClientAPI_SessionCache( { + 'namespace' => 'FS::ClientAPI::MyAccount', + } ); +} + 1; diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index ab5096891..48a6ba940 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -506,7 +506,8 @@ sub process_payment { } my %payby2fields = ( - 'CARD' => [ qw( paystart_month paystart_year payissue address1 address2 city state zip payip ) ], + 'CARD' => [ qw( paystart_month paystart_year payissue payip + address1 address2 city state zip country ) ], 'CHEK' => [ qw( ss paytype paystate stateid stateid_state payip ) ], ); @@ -527,8 +528,8 @@ sub process_payment { my $new = new FS::cust_main { $cust_main->hash }; if ($payby eq 'CARD' || $payby eq 'DCRD') { $new->set( $_ => $p->{$_} ) - foreach qw( payname paystart_month paystart_year payissue payip - address1 address2 city state zip payinfo ); + foreach qw( payinfo payname paystart_month paystart_year payissue payip + address1 address2 city state zip country ); $new->set( 'payby' => $p->{'auto'} ? 'CARD' : 'DCRD' ); } elsif ($payby eq 'CHEK' || $payby eq 'DCHK') { $new->set( $_ => $p->{$_} ) diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index 47f312ac0..058955037 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -86,8 +86,9 @@ $socket .= '.'.$tag if defined $tag && length($tag); ); @EXPORT_OK = ( keys(%autoload), - qw( regionselector regionselector_hashref - expselect popselector domainselector didselector ) + qw( regionselector regionselector_hashref location_form + expselect popselector domainselector didselector + ) ); $ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin'; @@ -550,6 +551,10 @@ State Zip or postal code +=item country + +Two-letter country code + =item payinfo Card number @@ -1436,6 +1441,52 @@ sub regionselector_hashref { }; } +=item location_form HASHREF | LIST + +Takes as input a hashref or list of key/value pairs with the following keys: + +=over 4 + +=item session_id + +Current customer session_id + +=item no_asterisks + +Omit red asterisks from required fields. + +=item address1_label + +Label for first address line. + +=back + +Returns an HTML fragment for a location form (address, city, state, zip, +country) + +=cut + +sub location_form { + my $param; + if ( ref($_[0]) ) { + $param = shift; + } else { + $param = { @_ }; + } + + my $session_id = delete $param->{'session_id'}; + + my $rv = mason_comp( 'session_id' => $session_id, + 'comp' => '/elements/location.html', + 'args' => [ %$param ], + ); + + #hmm. + $rv->{'error'} || $rv->{'output'}; + +} + + #=item expselect HASHREF | LIST # #Takes as input a hashref or list of key/value pairs with the following keys: diff --git a/fs_selfservice/FS-SelfService/cgi/card.html b/fs_selfservice/FS-SelfService/cgi/card.html index cf6d20d8d..c7db2b398 100644 --- a/fs_selfservice/FS-SelfService/cgi/card.html +++ b/fs_selfservice/FS-SelfService/cgi/card.html @@ -1,11 +1,11 @@ - Card number - + Card number + - + - - - - - - - - - - - + + + +<%= location_form( 'session_id' => $session_id, + 'no_asterisks' => 1, + #'address1_label' => 'Card billing address', + 'address1_label' => 'Card billing address', + ) +%> diff --git a/fs_selfservice/FS-SelfService/cgi/make_payment.html b/fs_selfservice/FS-SelfService/cgi/make_payment.html index a468d998a..da6e67ed2 100644 --- a/fs_selfservice/FS-SelfService/cgi/make_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/make_payment.html @@ -22,23 +22,23 @@
Exp.Exp.
Exact name on card
Card billing address - -
Address line 2 - -
City - - - - - - - - -
- - State - - Zip - -
-
Exact name on card
- - + - - + - - + <%= include('card') %> - - diff --git a/fs_selfservice/FS-SelfService/cgi/misc/counties.cgi b/fs_selfservice/FS-SelfService/cgi/misc/counties.cgi new file mode 100755 index 000000000..476fe09a4 --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/misc/counties.cgi @@ -0,0 +1,18 @@ +#!/usr/bin/perl -w + +use strict; +use CGI; +use FS::SelfService qw( mason_comp ); + +my $cgi = new CGI; + +my $rv = mason_comp( 'comp' => '/misc/counties.cgi', + 'query_string' => $cgi->query_string, #pass CGI params... + ); + +#hmm. +my $output = $rv->{'error'} || $rv->{'output'}; + +print $cgi->header( '-expires' => 'now' ). + $output; + diff --git a/fs_selfservice/FS-SelfService/cgi/misc/states.cgi b/fs_selfservice/FS-SelfService/cgi/misc/states.cgi new file mode 100755 index 000000000..f75f2ae1d --- /dev/null +++ b/fs_selfservice/FS-SelfService/cgi/misc/states.cgi @@ -0,0 +1,18 @@ +#!/usr/bin/perl -w + +use strict; +use CGI; +use FS::SelfService qw( mason_comp ); + +my $cgi = new CGI; + +my $rv = mason_comp( 'comp' => '/misc/states.cgi', + 'query_string' => $cgi->query_string, #pass CGI params... + ); + +#hmm. +my $output = $rv->{'error'} || $rv->{'output'}; + +print $cgi->header( '-expires' => 'now' ). + $output; + diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index ecf2553a3..4c7b1d86a 100644 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -664,7 +664,7 @@ package FS::SelfService::_selfservicecgi; #use FS::SelfService qw(regionselector expselect popselector); use HTML::Entities; -use FS::SelfService qw(regionselector popselector domainselector); +use FS::SelfService qw(regionselector popselector domainselector location_form); #false laziness w/agent.cgi sub include { diff --git a/httemplate/elements/location.html b/httemplate/elements/location.html index 6691bc84e..dbc567d4d 100644 --- a/httemplate/elements/location.html +++ b/httemplate/elements/location.html @@ -23,7 +23,7 @@ Example: NAME = "<%$pre%>address1" ID = "<%$pre%>address1" VALUE = "<% $object->get($pre.'address1') |h %>" - SIZE = 58 + SIZE = 54 onChange = "<% $onchange %>" <% $disabled %> <% $style %> @@ -38,7 +38,7 @@ Example: NAME = "<%$pre%>address2" ID = "<%$pre%>address2" VALUE = "<% $object->get($pre.'address2') |h %>" - SIZE = 58 + SIZE = 54 onChange = "<% $onchange %>" <% $disabled %> <% $style %> @@ -48,7 +48,7 @@ Example: - - - - - + + + @@ -82,7 +80,7 @@ Example: - + % if ( !$pre ) { @@ -126,7 +124,7 @@ my @counties = counties( $object->get($pre.'state'), $object->get($pre.'country'), ); my @county_style = (); -push @county_style, 'visibility:hidden' +push @county_style, 'display:none' # 'visibility:hidden' unless scalar(@counties) > 1; my $style = diff --git a/httemplate/elements/select-county.html b/httemplate/elements/select-county.html index 59f235a23..aa88abe96 100644 --- a/httemplate/elements/select-county.html +++ b/httemplate/elements/select-county.html @@ -58,10 +58,12 @@ Example: if ( countiesArray.length > 1 ) { what.form.<% $pre %>county.style.display = ''; - countyFormLabel.style.visibility = 'visible'; + //countyFormLabel.style.visibility = 'visible'; + countyFormLabel.style.display = ''; } else { what.form.<% $pre %>county.style.display = 'none'; - countyFormLabel.style.visibility = 'hidden'; + //countyFormLabel.style.visibility = 'hidden'; + countyFormLabel.style.display = 'none'; } //run the callback -- cgit v1.2.1 From 9e8452ef043446036fa27d3cf668ebf25bade7b8 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 25 May 2009 03:59:22 +0000 Subject: international self-service payments, RT#1592 --- fs_selfservice/FS-SelfService/cgi/selfservice.cgi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index 4c7b1d86a..148fc4ddc 100644 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -366,12 +366,15 @@ sub payment_results { $cgi->param('city') =~ /^(.{0,80})$/ or die "illegal city"; my $city = $1; - $cgi->param('state') =~ /^(.{2})$/ or die "illegal state"; + $cgi->param('state') =~ /^(.{80})$/ or die "illegal state"; my $state = $1; $cgi->param('zip') =~ /^(.{0,10})$/ or die "illegal zip"; my $zip = $1; + $cgi->param('country') =~ /^(.{0,2})$/ or die "illegal country"; + my $country = $1; + my $save = 0; $save = 1 if $cgi->param('save'); @@ -395,6 +398,7 @@ sub payment_results { 'city' => $city, 'state' => $state, 'zip' => $zip, + 'country' => $country, 'save' => $save, 'auto' => $auto, 'paybatch' => $paybatch, -- cgit v1.2.1 From 208add41d52153ccff338fe0f1eafbc0c462a2ed Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 25 May 2009 22:42:21 +0000 Subject: fix total links on sales graph when a package class is specified, RT#5449 --- httemplate/graph/cust_bill_pkg.cgi | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/httemplate/graph/cust_bill_pkg.cgi b/httemplate/graph/cust_bill_pkg.cgi index d7cae8055..a96eed779 100644 --- a/httemplate/graph/cust_bill_pkg.cgi +++ b/httemplate/graph/cust_bill_pkg.cgi @@ -9,7 +9,7 @@ 'links' => \@links, 'remove_empty' => 1, 'bottom_total' => 1, - 'bottom_link' => "$link;", + 'bottom_link' => $bottom_link, 'agentnum' => $agentnum, ) %> @@ -27,21 +27,42 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { } my $title = $sel_agent ? $sel_agent->agent.' ' : ''; -#false lazinessish w/search/cust_pkg.cgi +my $link = "${p}search/cust_bill_pkg.cgi?nottax=1;include_comp_cust=1"; +my $bottom_link = "$link;"; + +#classnum (here) +# 0: all classes +# not specified: empty class +# N: classnum +#classnum (link) +# not specified: all classes +# 0: empty class +# N: classnum + +#false lazinessish w/FS::cust_pkg::search_sql (previously search/cust_pkg.cgi) my $classnum = 0; my @pkg_class = (); if ( $cgi->param('classnum') =~ /^(\d*)$/ ) { $classnum = $1; - if ( $classnum ) { + + if ( $classnum ) { #a specific class + @pkg_class = ( qsearchs('pkg_class', { 'classnum' => $classnum } ) ); die "classnum $classnum not found!" unless $pkg_class[0]; $title .= $pkg_class[0]->classname.' '; - } elsif ( $classnum eq '' ) { + $bottom_link .= "classnum=$classnum;"; + + } elsif ( $classnum eq '' ) { #the empty class + $title .= 'Empty class '; @pkg_class = ( '(empty class)' ); - } elsif ( $classnum eq '0' ) { + $bottom_link .= "classnum=0;"; + + } elsif ( $classnum eq '0' ) { #all classes + @pkg_class = qsearch('pkg_class', {} ); # { 'disabled' => '' } ); push @pkg_class, '(empty class)'; + } } #eslaf @@ -57,8 +78,6 @@ my @labels = (); my @colors = (); my @links = (); -my $link = "${p}search/cust_bill_pkg.cgi?nottax=1;include_comp_cust=1"; - foreach my $agent ( $sel_agent || qsearch('agent', { 'disabled' => '' } ) ) { my $col_scheme = Color::Scheme->new -- cgit v1.2.1 From 8d9be02c9965db4c4a48a2221455160685a95462 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 26 May 2009 01:35:16 +0000 Subject: add a config option for some basic tax grouping by name, RT#5446 --- FS/FS/Conf.pm | 9 ++++++- httemplate/search/report_tax.cgi | 57 ++++++++++++++++++++++++++++----------- httemplate/search/report_tax.html | 36 ++++++++++++++++++++----- 3 files changed, 79 insertions(+), 23 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 87e8517de..8b27610a7 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1380,7 +1380,7 @@ worry that config_items is freeside-specific and icky. { 'key' => 'selfservice_server-base_url', 'section' => '', - 'description' => 'Base URL for the self-service web interface - necessary for special provisioning widgets to find their way.', + 'description' => 'Base URL for the self-service web interface - necessary for some widgets to find their way, including retrieval of non-US state information and phone number provisioning.', 'type' => 'text', }, @@ -2802,6 +2802,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'text', }, + { + 'key' => 'tax-report_groups', + 'section' => '', + 'description' => 'List of grouping possibilities for tax names on reports, one per line, "label op value" (op can be = or !=).', + 'type' => 'textarea', + }, + ); 1; diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index a7630dd2d..643ba52f3 100755 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -174,7 +174,7 @@ <<%$td%>>Total <<%$td%> ALIGN="right"> <% &$money_sprintf( $tax ) %> + ><% &$money_sprintf( $tot_tax ) %> @@ -275,8 +275,16 @@ if ( $conf->exists('tax-pkg_address') ) { "WHERE 0 < ( SELECT COUNT(*) FROM cust_main WHERE $gotcust LIMIT 1 )"; } -my($total, $tot_taxable, $owed, $tax) = ( 0, 0, 0, 0 ); +#tax-report_groups filtering +my($group_op, $group_value) = ( '', '' ); +if ( $cgi->param('report_group') =~ /^(=|!=) (.*)$/ ) { + ( $group_op, $group_value ) = ( $1, $2 ); +} +my $skipping_out = $group_op ? 1 : 0; #in case there are other reasons + +my( $total, $tot_taxable, $tot_owed ) = ( 0, 0, 0 ); my( $exempt_cust, $exempt_pkg, $exempt_monthly ) = ( 0, 0, 0 ); + my $out = 'Out of taxable region(s)'; my %regions = (); @@ -326,8 +334,8 @@ foreach my $r ( qsearch({ 'table' => 'cust_main_county', my $t_sql = "SELECT SUM(cust_bill_pkg.setup+cust_bill_pkg.recur) $fromwhere AND $nottax"; my $t = scalar_sql($r, \@param, $t_sql); - $total += $t; $regions{$label}->{'total'} += $t; + $total += $t unless $label eq $out && $skipping_out; #if ( $label eq $out ) {# && $t ) { # warn "adding $t for ". @@ -356,8 +364,8 @@ foreach my $r ( qsearch({ 'table' => 'cust_main_county', $fromwhere AND $nottax AND tax = 'Y' " ); - $exempt_cust += $x_cust; $regions{$label}->{'exempt_cust'} += $x_cust; + $exempt_cust += $x_cust unless $label eq $out && $skipping_out; ## calculate package-exemption for this region @@ -384,8 +392,8 @@ foreach my $r ( qsearch({ 'table' => 'cust_main_county', AND ( tax != 'Y' OR tax IS NULL ) " ); - $exempt_pkg += $x_pkg; $regions{$label}->{'exempt_pkg'} += $x_pkg; + $exempt_pkg += $x_pkg unless $label eq $out && $skipping_out; ## calculate monthly exemption (texas tax) for this region @@ -404,16 +412,17 @@ foreach my $r ( qsearch({ 'table' => 'cust_main_county', # $taxable -= $x_monthly; # } - $exempt_monthly += $x_monthly; $regions{$label}->{'exempt_monthly'} += $x_monthly; + $exempt_monthly += $x_monthly unless $label eq $out && $skipping_out; my $taxable = $t - $x_cust - $x_pkg - $x_monthly; - $tot_taxable += $taxable; $regions{$label}->{'taxable'} += $taxable; + $tot_taxable += $taxable unless $label eq $out && $skipping_out; - $owed += $taxable * ($r->tax/100); - $regions{$label}->{'owed'} += $taxable * ($r->tax/100); + my $owed = $taxable * ($r->tax/100); + $regions{$label}->{'owed'} += $owed; + $tot_owed += $owed unless $label eq $out && $skipping_out; if ( defined($regions{$label}->{'rate'}) && $regions{$label}->{'rate'} != $r->tax.'%' ) { @@ -474,6 +483,7 @@ my $_taxamount_sub = sub { scalar_sql($r, \@taxparam, $sql ); }; +my $tot_tax = 0; #foreach my $label ( keys %regions ) { foreach my $r ( qsearch(\%qsearch) ) { @@ -486,8 +496,8 @@ foreach my $r ( qsearch(\%qsearch) ) { my $x = &{$_taxamount_sub}($r); - $tax += $x unless $cgi->param('show_taxclasses'); $regions{$label}->{'tax'} += $x; + $tot_tax += $x unless $cgi->param('show_taxclasses'); } @@ -508,17 +518,34 @@ if ( $cgi->param('show_taxclasses') ) { ); $base_regions{$base_label}->{'tax'} += $x; - $tax += $x; + $tot_tax += $x; } } +my @regions = keys %regions; + +#tax-report_groups filtering +if ( $group_op ) { + @regions = grep { + if ( $_ eq $out ) { #don't display "out of taxable region" in this case + 0; + } elsif ( $group_op eq '=' ) { + $_ =~ /^$group_value \(/; + } elsif ( $group_op eq '!=' ) { + $_ !~ /^$group_value \(/; + } else { + die "guru meditation #00de: group_op $group_op\n"; + } + } @regions; +} + #ordering -my @regions = +@regions = map $regions{$_}, sort { ( ($a eq $out) cmp ($b eq $out) ) || ($b cmp $a) } - keys %regions; + @regions; my @base_regions = map $base_regions{$_}, @@ -534,8 +561,8 @@ push @regions, { 'exempt_monthly' => $exempt_monthly, 'taxable' => $tot_taxable, 'rate' => '', - 'owed' => $owed, - 'tax' => $tax, + 'owed' => $tot_owed, + 'tax' => $tot_tax, }; #-- diff --git a/httemplate/search/report_tax.html b/httemplate/search/report_tax.html index e5ffa9a17..8640e0ee7 100755 --- a/httemplate/search/report_tax.html +++ b/httemplate/search/report_tax.html @@ -4,29 +4,49 @@
Amount Due + Amount Due
$<%=sprintf("%.2f",$balance)%>
Payment amount + Payment amount
$">
Card type + Card type
+ Remember this information
+ NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }"> Charge future payments to this card automatically
<%$r%>City + <% $style %> > - ><%$r%>County - <% include('/elements/select-county.html', %select_hash ) %> <%$r%>State + ><%$r%>County<% include('/elements/select-county.html', %select_hash ) %><%$r%>State <% include('/elements/select-state.html', %select_hash ) %> <%$r%>Zip
<%$r%>Country<% include('/elements/select-country.html', %select_hash ) %><% include('/elements/select-country.html', %select_hash ) %>
+% if ( $conf->config('tax-report_groups') ) { +% my @lines = $conf->config('tax-report_groups'); + + + + + + +% } + <% include( '/elements/tr-select-agent.html', 'disable_empty'=>0 ) %> <% include( '/elements/tr-input-beginning_ending.html' ) %> -% my $conf = new FS::Conf; -% if ( $conf->exists('enable_taxclasses') ) { -% +% if ( $conf->exists('enable_taxclasses') ) { % } -% my @pkg_class = qsearch('pkg_class', {}); -% if ( @pkg_class ) { -% +% my @pkg_class = qsearch('pkg_class', {}); +% if ( @pkg_class ) { % } -
Tax group + +
Show tax classes
Show package classes

@@ -39,4 +59,6 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); +my $conf = new FS::Conf; + -- cgit v1.2.1 From f8cde7e13b431e0f159906b96b0c4d02382a875d Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 26 May 2009 01:43:30 +0000 Subject: add a config option for some basic tax grouping by name, RT#5446 --- httemplate/search/report_tax.cgi | 2 +- httemplate/search/report_tax.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi index 643ba52f3..9f0ad990a 100755 --- a/httemplate/search/report_tax.cgi +++ b/httemplate/search/report_tax.cgi @@ -1,4 +1,4 @@ -<% include("/elements/header.html", "$agentname Sales Tax Report - ". +<% include("/elements/header.html", "$agentname Tax Report - ". ( $beginning ? time2str('%h %o %Y ', $beginning ) : '' diff --git a/httemplate/search/report_tax.html b/httemplate/search/report_tax.html index 8640e0ee7..217f48146 100755 --- a/httemplate/search/report_tax.html +++ b/httemplate/search/report_tax.html @@ -8,7 +8,7 @@ % my @lines = $conf->config('tax-report_groups'); - Tax group + Tax group !; }, - fields('cdr'), #XXX fill in some pretty-print + @fields, #XXX fill in some pretty-print #processing, etc. ], @@ -156,4 +156,36 @@ my $qsearch = join(' AND ', @qsearch); $qsearch = ( scalar(keys %$hashref) ? ' AND ' : ' WHERE ' ) . $qsearch if $qsearch; +### +# display fields +### + +#XXX fill in some (more) nice names +my %header = ( + 'calldate' => 'Call Date', + 'clid' => 'Caller ID', + 'charged_party' => 'Charged party', + 'src' => 'Source', + 'dst' => 'Destination', + 'dcontext' => 'Destination Context', + 'channel' => 'Channel', + 'dstchannel' => 'Destination Channel', + 'freesidestatus' => 'Freeside status', +); + +my @first = qw( acctid calldate clid charged_party src dst dcontext ); +my %first = map { $_=>1 } @first; + +my @fields = ( @first, grep !$first{$_}, fields('cdr') ); + +my @header = map { + if ( exists($header{$_}) ) { + $header{$_}; + } else { + my $header = $_; + $header =~ s/\_/ /g; + ucfirst($header); + } + } @fields; + -- cgit v1.2.1 From e13421f071b4a7b872e6d40205ca736125cb294d Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 30 May 2009 02:31:39 +0000 Subject: require svc_acct-usage_threshold to be set explicitly, don't default to 80% --- FS/FS/Conf.pm | 2 +- FS/FS/svc_acct.pm | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index cf7e49fe5..0664c1444 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2014,7 +2014,7 @@ worry that config_items is freeside-specific and icky. { 'key' => 'svc_acct-usage_threshold', 'section' => 'billing', - 'description' => 'The threshold (expressed as percentage) of acct.seconds or acct.up|down|totalbytes at which a warning message is sent to a service holder. Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd. Defaults to 80.', + 'description' => 'The threshold (expressed as percentage) of acct.seconds or acct.up|down|totalbytes at which a warning message is sent to a service holder. Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd.', 'type' => 'text', }, diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 1a42e6517..e5be29473 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -539,12 +539,13 @@ sub insert { my %values = $part_pkg->usage_valuehash; my $multiplier = $conf->exists('svc_acct-usage_threshold') ? 1 - $conf->config('svc_acct-usage_threshold')/100 - : 0.20; + : 0.20; #doesn't matter foreach ( keys %values ) { next if $self->getfield($_); $self->setfield( $_, $values{$_} ); - $self->setfield( $_. '_threshold', int( $values{$_} * $multiplier ) ); + $self->setfield( $_. '_threshold', int( $values{$_} * $multiplier ) ) + if $conf->exists('svc_acct-usage_threshold'); } } -- cgit v1.2.1 From 467b269c5cacef3e8486e2288f1b0eeec8fea088 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 30 May 2009 03:14:13 +0000 Subject: add ability for prepaid packages to have usage limits and cancel if they're hit, RT#4995 --- FS/FS/part_pkg/flat.pm | 78 +++++++++++++++++++++++++++++------------------ FS/FS/part_pkg/prepaid.pm | 16 +++++++++- FS/FS/svc_acct.pm | 22 +++++++++++++ 3 files changed, 85 insertions(+), 31 deletions(-) diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index 009e54c78..171885770 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -1,7 +1,10 @@ package FS::part_pkg::flat; use strict; -use vars qw(@ISA %info); +use vars qw( @ISA %info + %usage_fields %usage_recharge_fields + @usage_fieldorder @usage_recharge_fieldorder + ); use Tie::IxHash; #use FS::Record qw(qsearch); use FS::UI::bytecount; @@ -14,30 +17,8 @@ tie my %temporalities, 'Tie::IxHash', 'preceding' => "Preceding (past)", ; -%info = ( - 'name' => 'Flat rate (anniversary billing)', - 'shortname' => 'Anniversary', - 'fields' => { - 'setup_fee' => { 'name' => 'Setup fee for this package', - 'default' => 0, - }, - 'recur_fee' => { 'name' => 'Recurring fee for this package', - 'default' => 0, - }, - - #false laziness w/voip_cdr.pm - 'recur_temporality' => { 'name' => 'Charge recurring fee for period', - 'type' => 'select', - 'select_options' => \%temporalities, - }, +%usage_fields = ( - 'unused_credit' => { 'name' => 'Credit the customer for the unused portion'. - ' of service at cancellation', - 'type' => 'checkbox', - }, - 'externalid' => { 'name' => 'Optional External ID', - 'default' => '', - }, 'seconds' => { 'name' => 'Time limit for this package', 'default' => '', 'check' => sub { shift =~ /^\d*$/ }, @@ -60,6 +41,10 @@ tie my %temporalities, 'Tie::IxHash', 'format' => \&FS::UI::bytecount::display_bytecount, 'parse' => \&FS::UI::bytecount::parse_bytecount, }, +); + +%usage_recharge_fields = ( + 'recharge_amount' => { 'name' => 'Cost of recharge for this package', 'default' => '', 'check' => sub { shift =~ /^\d*(\.\d{2})?$/ }, @@ -94,13 +79,46 @@ tie my %temporalities, 'Tie::IxHash', 'package recharge', 'type' => 'checkbox', }, +); + +@usage_fieldorder = qw( seconds upbytes downbytes totalbytes ); +@usage_recharge_fieldorder = qw( + recharge_amount recharge_seconds recharge_upbytes + recharge_downbytes recharge_totalbytes + usage_rollover recharge_reset +); + +%info = ( + 'name' => 'Flat rate (anniversary billing)', + 'shortname' => 'Anniversary', + 'fields' => { + 'setup_fee' => { 'name' => 'Setup fee for this package', + 'default' => 0, + }, + 'recur_fee' => { 'name' => 'Recurring fee for this package', + 'default' => 0, + }, + + #false laziness w/voip_cdr.pm + 'recur_temporality' => { 'name' => 'Charge recurring fee for period', + 'type' => 'select', + 'select_options' => \%temporalities, + }, + + %usage_fields, + %usage_recharge_fields, + + 'unused_credit' => { 'name' => 'Credit the customer for the unused portion'. + ' of service at cancellation', + 'type' => 'checkbox', + }, + 'externalid' => { 'name' => 'Optional External ID', + 'default' => '', + }, }, - 'fieldorder' => [qw( setup_fee recur_fee recur_temporality unused_credit - seconds upbytes downbytes totalbytes - recharge_amount recharge_seconds recharge_upbytes - recharge_downbytes recharge_totalbytes - usage_rollover recharge_reset externalid - ) + 'fieldorder' => [ qw( setup_fee recur_fee recur_temporality unused_credit ), + @usage_fieldorder, @usage_recharge_fieldorder, + qw( externalid ), ], 'weight' => 10, ); diff --git a/FS/FS/part_pkg/prepaid.pm b/FS/FS/part_pkg/prepaid.pm index 4499d0e52..23d340167 100644 --- a/FS/FS/part_pkg/prepaid.pm +++ b/FS/FS/part_pkg/prepaid.pm @@ -12,6 +12,11 @@ tie %recur_action, 'Tie::IxHash', 'cancel' => 'cancel', ; +tie my %overlimit_action, 'Tie::IxHash', + 'overlimit' => 'Default overlimit processing', + 'cancel' => 'Cancel', +; + %info = ( 'name' => 'Prepaid, flat rate', #'name' => 'Prepaid (no automatic recurring)', #maybe use it here too @@ -27,8 +32,17 @@ tie %recur_action, 'Tie::IxHash', 'type' => 'select', 'select_options' => \%recur_action, }, + %FS::part_pkg::flat::usage_fields, + 'overlimit_action' => { 'name' => 'Action to take upon reaching a usage limit.', + 'type' => 'select', + 'select_options' => \%overlimit_action, + }, + #XXX if you set overlimit_action to 'cancel', should also have the ability + # to select a reason }, - 'fieldorder' => [ 'setup_fee', 'recur_fee', 'recur_action', ], + 'fieldorder' => [ qw( setup_fee recur_fee recur_action ), + @FS::part_pkg::flat::usage_fieldorder, + ], 'weight' => 25, ); diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index e5be29473..4669588d5 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1772,6 +1772,28 @@ sub _op_usage { die "Can't update $column for svcnum". $self->svcnum if $rv == 0; + #overlimit_action eq 'cancel' handling + my $cust_pkg = $self->cust_svc->cust_pkg; + if ( $cust_pkg + && $cust_pkg->part_pkg->option('overlimit_action', 1) eq 'cancel' + && $op eq '-' && &{$op2condition{$op}}($self, $column, $amount) + ) + { + + my $error = $cust_pkg->cancel; #XXX should have a reason + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error cancelling: $error"; + } + + #nothing else is relevant if we're cancelling, so commit & return success + warn "$me update successful; committing\n" + if $DEBUG; + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return ''; + + } + my $action = $op2action{$op}; if ( &{$op2condition{$op}}($self, $column, $amount) && -- cgit v1.2.1 From 29615c5145652c3f0bc293d468493709517b9fd9 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 30 May 2009 03:40:12 +0000 Subject: and enable overlimit_action, RT#4995 --- FS/FS/part_pkg/prepaid.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/part_pkg/prepaid.pm b/FS/FS/part_pkg/prepaid.pm index 23d340167..cff165a5d 100644 --- a/FS/FS/part_pkg/prepaid.pm +++ b/FS/FS/part_pkg/prepaid.pm @@ -41,7 +41,7 @@ tie my %overlimit_action, 'Tie::IxHash', # to select a reason }, 'fieldorder' => [ qw( setup_fee recur_fee recur_action ), - @FS::part_pkg::flat::usage_fieldorder, + @FS::part_pkg::flat::usage_fieldorder, 'overlimit_action', ], 'weight' => 25, ); -- cgit v1.2.1 From a0b2c1a1ac9da3b33bc088dab0af77f6555428f7 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 30 May 2009 10:45:43 +0000 Subject: add transnexus format, RT#5229 --- FS/FS/cdr.pm | 2 +- FS/FS/cdr/transnexus.pm | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 FS/FS/cdr/transnexus.pm diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index 421fd2bb8..ab87a6893 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -710,7 +710,7 @@ sub _cdr_date_parse { #$date =~ /^\s*(\d{4})[\-\/]\(\d{1,2})[\-\/](\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})\s*$/ #taqua #2007-10-31 08:57:24.113000000 - if ( $date =~ /^\s*(\d{4})\D(\d{1,2})\D(\d{1,2})\s+(\d{1,2})\D(\d{1,2})\D(\d{1,2})(\D|$)/ ) { + if ( $date =~ /^\s*(\d{4})\D(\d{1,2})\D(\d{1,2})\D+(\d{1,2})\D(\d{1,2})\D(\d{1,2})(\D|$)/ ) { ($year, $mon, $day, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 ); } elsif ( $date =~ /^\s*(\d{1,2})\D(\d{1,2})\D(\d{4})\s+(\d{1,2})\D(\d{1,2})\D(\d{1,2})(\D|$)/ ) { ($mon, $day, $year, $hour, $min, $sec) = ( $1, $2, $3, $4, $5, $6 ); diff --git a/FS/FS/cdr/transnexus.pm b/FS/FS/cdr/transnexus.pm new file mode 100644 index 000000000..573a8b16d --- /dev/null +++ b/FS/FS/cdr/transnexus.pm @@ -0,0 +1,65 @@ +package FS::cdr::transnexus; + +use strict; +use base qw( FS::cdr ); +use vars qw( %info ); +use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker ); + +%info = ( + 'name' => 'Transnexus', + 'weight' => 18, + 'type' => 'csv', + 'sep_char' => "\t", + + #listref of what to do with each field from the CDR, in order + 'import_fields' => [ + + _cdr_date_parser_maker('startddate'), #O_CallStartTime + 'src', #CallingNumberReported + 'dst', #CalledNumberReported + 'channel', #SourceDeviceName / O_ReportingDeviceName + 'dstchannel', #O_ReportingDeviceName / DestinationDeviceName + 'clid', #CallId + 'uniqueid', #TransactionId + 'duration', #RatedDuration + 'billsec', #O_BillingDuration + 'upstream_price', #O_BillingAmountCustCurr + ], +); + +1; + +__END__ + +O_CallStartTime - Date and time stamp of the call setup as reported in the CDR from the source device. + +CallingNumberReported - Calling number from the source device reported in authorization request to the OSPrey server. + +CalledNumberReported - Called number from the source device reported in authorization request to the OSPrey server. + +---- +1.1.1 Customer CDR Archive File + +SourceDeviceName - The IP address or Domain Name of the device which is the call source. + +O_ReportingDeviceName - IP address or Domain Name of the source (Originating) device reporting the CDR to the OSPrey Server. If a proxy is used, (such as SIP proxy for signaling or FreeRADIUS for CDR reporting) this field is the IP address of the proxy device, not the actual source device. + +--- +or 1.1.2 Provider CDR Archive File + +O_ReportingDeviceName - IP address or Domain Name of the source (Originating) device reporting the CDR to the OSPrey Server. If a proxy is used, (such as SIP proxy for signaling or FreeRADIUS for CDR reporting) this field is the IP address of the proxy device, not the actual source device. + +DestinationDeviceName - The IP address or Domain Name of the destination device. + +---- + +CallId - The Call Identifier generated by the source VoIP device. + +TransactionId - The unique Transaction Identification number created by the OSPrey server for each call + +RatedDuration - The rateable duration calculated by NexOSS. + +O_BillingDuration - The duration used to calculate the billable amount for a call from the source (Originating) network. This value is derived from RatedDuration and rounded up based on the ¿First Increment¿ or ¿Next Increment¿ rules defined in the Product or Customer Rate Plan used to rate the call. + +O_BillingAmountCustCurr - Amount billable to the source (Originating) Customer. Provided in the currency of the Product or Customer Rate Plan. + -- cgit v1.2.1 From 678751e266c03c9736ee56f14098227269e0e50a Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 30 May 2009 11:14:31 +0000 Subject: quick hacked-up copy of freeside-cdr-sftp_and_import for transnexus directory structure, RT#5229 --- bin/cdr-transnexus.import | 142 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100755 bin/cdr-transnexus.import diff --git a/bin/cdr-transnexus.import b/bin/cdr-transnexus.import new file mode 100755 index 000000000..ee9a200dc --- /dev/null +++ b/bin/cdr-transnexus.import @@ -0,0 +1,142 @@ +#!/usr/bin/perl + +use strict; +use Getopt::Std; +use Net::SFTP::Foreign; +use FS::UID qw(adminsuidsetup datasrc); +use FS::cdr; + +### +# parse command line +### + +use vars qw( $opt_p $opt_d $opt_v ); +getopts('v'); + +$opt_p = 'last'; +$opt_d = 'done'; + +my $user = shift or die &usage; +adminsuidsetup $user; + +# %%%FREESIDE_CACHE%%% +my $cachedir = '/usr/local/etc/freeside/cache.'. datasrc. '/cdrs'; +mkdir $cachedir unless -d $cachedir; + +#my $format = shift or die &usage; +my $format = 'transnexus'; + +use vars qw( $servername ); +$servername = shift or die &usage; + +my $DIR = '/home/ossadmin/OSS/nexoss/CDR_ARCHIVE_BY_ACCOUNT'; + +### +# get the file list +### + +warn "Retreiving directory listing\n" if $opt_v; + +my $ls_sftp = sftp(); + +my $lsdir = $ls_sftp->ls($DIR); + +### +# import each file in each dir +### + +foreach my $dir ( @$lsdir ) { + + my $dirname = $dir->{filename}; + warn "Scanning dir $dirname\n" if $opt_v; + + my $ls = $ls_sftp->ls("$DIR/$dirname", wanted => qr/^$opt_p.*-CDRs$/i ); + + foreach my $file ( @$ls ) { + + my $filename = $file->{filename}; + warn "Downloading $filename\n" if $opt_v; + + #get the file + my $get_sftp = sftp(); + $get_sftp->get("$DIR/$dirname/$filename", "$cachedir/$filename") + or die "Can't get $filename: ". $get_sftp->error; + + warn "Processing $filename\n" if $opt_v; + + my $error = FS::cdr::batch_import( { + 'file' => "$cachedir/$filename", + 'format' => $format, + 'params' => { 'cdrbatch' => $filename, }, + 'empty_ok' => 1, + } ); + die $error if $error; + + if ( $opt_d ) { + my $mv_sftp = sftp(); + $mv_sftp->mkdir("$DIR/$dirname/$opt_d"); + $mv_sftp->rename( "$DIR/$dirname/$filename", + "$DIR/$dirname/$opt_d/$filename" ) + or die "can't move $filename to $opt_d: ". $mv_sftp->error; + } + + unlink "$cachedir/$filename"; + + } + +} + +### +# subs +### + +sub usage { + "Usage: \n cdr-transnexus.import [ -v ] user [sftpuser@]servername\n"; +} + +use vars qw( $sftp ); + +sub sftp { + + #reuse connections + return $sftp if $sftp && $sftp->cwd; + + my %sftp = ( host => $servername ); + + $sftp = Net::SFTP::Foreign->new(%sftp); + $sftp->error and die "SFTP connection failed: ". $sftp->error; + + $sftp; +} + +=head1 NAME + +cdr.sftp_and_import - Download CDR files from a remote server via SFTP + +=head1 SYNOPSIS + + cdr-transnexus.import [ -v ] user [sftpuser@]servername + +=head1 DESCRIPTION + +Command line tool to download CDR files from a remote server via SFTP and then +import them into the database. + +-v: verbose + +user: freeside username + +[sftpuser@]servername: remote server + +=head1 BUGS + +Hacked up copy of freeside-cdr-sftp_and_import + +=head1 SEE ALSO + +L + +=cut + +1; + -- cgit v1.2.1 From 69fe663ff9595ed47a77826920ffdda8a45a4d23 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 30 May 2009 11:21:01 +0000 Subject: clid is base-64 encoded, huh, RT#5229 --- FS/FS/cdr/transnexus.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/FS/FS/cdr/transnexus.pm b/FS/FS/cdr/transnexus.pm index 573a8b16d..0ed7ad4ef 100644 --- a/FS/FS/cdr/transnexus.pm +++ b/FS/FS/cdr/transnexus.pm @@ -3,6 +3,7 @@ package FS::cdr::transnexus; use strict; use base qw( FS::cdr ); use vars qw( %info ); +use MIME::Base64; use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker ); %info = ( @@ -14,12 +15,12 @@ use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker ); #listref of what to do with each field from the CDR, in order 'import_fields' => [ - _cdr_date_parser_maker('startddate'), #O_CallStartTime + _cdr_date_parser_maker('startddate'), #O_CallStartTime 'src', #CallingNumberReported 'dst', #CalledNumberReported 'channel', #SourceDeviceName / O_ReportingDeviceName 'dstchannel', #O_ReportingDeviceName / DestinationDeviceName - 'clid', #CallId + sub { $_[0]->clid( decode_base64($_[1]) ); }, #CallId 'uniqueid', #TransactionId 'duration', #RatedDuration 'billsec', #O_BillingDuration -- cgit v1.2.1 From d40b234aeb9d77f3a780d919e7367e155d8d2a36 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 30 May 2009 12:15:23 +0000 Subject: very long transnexus filenames, RT#5229 --- FS/FS/Schema.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 238058374..1f8fa8fa1 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -2091,7 +2091,7 @@ sub tables_hashref { #NULL, done (or something) 'freesiderewritestatus', 'varchar', 'NULL', 32, '', '', - 'cdrbatch', 'varchar', 'NULL', $char_d, '', '', + 'cdrbatch', 'varchar', 'NULL', 255, '', '', ], 'primary_key' => 'acctid', -- cgit v1.2.1 From 6ef8f43327f534f8e6f03265ecd97bd654730c07 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 31 May 2009 04:57:00 +0000 Subject: necessary for bin/cdr-netsapeins.import --- FS/FS/part_export/netsapiens.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/FS/FS/part_export/netsapiens.pm b/FS/FS/part_export/netsapiens.pm index e19e95cb4..172f7b053 100644 --- a/FS/FS/part_export/netsapiens.pm +++ b/FS/FS/part_export/netsapiens.pm @@ -39,9 +39,11 @@ sub ns_command { my @args = ( $command ); if ( $method eq 'PUT' ) { - my $content = $method eq 'PUT' ? $ns->buildQuery( { @_ } ) : ''; + my $content = $ns->buildQuery( { @_ } ); $content =~ s/^\?//; push @args, $content; + } elsif ( $method eq 'GET' ) { + $args[0] .= $ns->buildQuery( { @_ } ); } my $auth = -- cgit v1.2.1 From 650c968bf1493c601dcf1b57d98ef0bdb1a2caa6 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 31 May 2009 05:15:44 +0000 Subject: start of netsapeins cdr import, will finish up when can connect again, RT#5226 --- bin/cdr-netsapiens.import | 207 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100755 bin/cdr-netsapiens.import diff --git a/bin/cdr-netsapiens.import b/bin/cdr-netsapiens.import new file mode 100755 index 000000000..80922556a --- /dev/null +++ b/bin/cdr-netsapiens.import @@ -0,0 +1,207 @@ +#!/usr/bin/perl +# +# */5 * * * /home/ivan/freeside/bin/cdr-netsapiens.import ivan exportnum + +use strict; +use vars qw( $DEBUG ); +use REST::Client; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearchs); +use FS::part_export; +use FS::cdr; + +$DEBUG = 2; + +my $user = shift or die &usage; +adminsuidsetup $user; + +my $exportnum = shift or die &usage; +my $part_export = qsearchs('part_export', { 'exportnum' => $exportnum } ) + or die "unknown exportnum $exportnum\n"; + +#find max time_release +#SELECT MAX( +#2009-02-19 20:17:37 +my $time_release = '2009-01-01 00:00:00'; + +#retreive CDRs >= this time +#XXX (in pages, this tops out at 20) _start=>0, _limit=>20 + +my $ns = $part_export->ns_command( 'GET', '/cdr/', + 'time_release' => '$time_release,', + '_sort' => '+time_release', + ); + +#loop over them, double check duplicates, insert the rest + +my $content = $ns->responseContent; + +#20090219201719000016@SkyNet360.Com +#

- - - - diff --git a/httemplate/search/unapplied_cust_pay.html b/httemplate/search/unapplied_cust_pay.html index 35abd6bbc..8d064d174 100755 --- a/httemplate/search/unapplied_cust_pay.html +++ b/httemplate/search/unapplied_cust_pay.html @@ -2,7 +2,8 @@ #'title' => 'Prepaid Balance Aging Summary', #??? 'title' => 'Unapplied Payments Aging Summary', 'range_sub' => \&unapplied_payments, - ); + ) +%> <%init> die "access denied" @@ -11,35 +12,16 @@ die "access denied" <%once> -#Example: -# -# my $balance = balance( -# $start, $end, -# 'no_as' => 1, #set to true when using in a WHERE clause (supress AS clause) -# #or 0 / omit when using in a SELECT clause as a column -# # ("AS balance_$start_$end") -# 'sum' => 1, #set to true to get a SUM() of the values, for totals -# -# #obsolete? options for totals (passed to cust_main::balance_date_sql) -# 'total' => 1, #set to true to remove all customer comparison clauses -# 'join' => $join, #JOIN clause -# 'where' => \@where, #WHERE clause hashref (elements "AND"ed together) -# ) - -#sub balance { sub unapplied_payments { my($start, $end, %opt) = @_; -#XXX fill-in -# #handle start and end ranges (86400 = 24h * 60m * 60s) -# my $str2time = str2time_sql; -# my $closing = str2time_sql_closing; -# $start = $start ? "( $str2time now() $closing - ".($start * 86400). ' )' : ''; -# $end = $end ? "( $str2time now() $closing - ".($end * 86400). ' )' : ''; -# -# #$opt{'unapplied_date'} = 1; -# -# FS::cust_main->balance_date_sql( $start, $end, %opt ). + #handle start and end ranges (86400 = 24h * 60m * 60s) + my $str2time = str2time_sql; + my $closing = str2time_sql_closing; + $start = $start ? "( $str2time now() $closing - ".($start * 86400). ' )' : ''; + $end = $end ? "( $str2time now() $closing - ".($end * 86400). ' )' : ''; + + FS::cust_main->unapplied_payments_date_sql( $start, $end ); } -- cgit v1.2.1 From 1cf09d80c37393560d1fd831ec1aa04354e09d6a Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 9 Jul 2009 23:58:43 +0000 Subject: add -r option --- FS/bin/freeside-cdr-sftp_and_import | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/FS/bin/freeside-cdr-sftp_and_import b/FS/bin/freeside-cdr-sftp_and_import index c4484f1d4..18de94ddf 100755 --- a/FS/bin/freeside-cdr-sftp_and_import +++ b/FS/bin/freeside-cdr-sftp_and_import @@ -10,8 +10,8 @@ use FS::cdr; # parse command line ### -use vars qw( $opt_p $opt_e $opt_d $opt_v ); -getopts('p:e:d:v'); +use vars qw( $opt_p $opt_r $opt_e $opt_d $opt_v ); +getopts('p:r:e:d:v'); $opt_e ||= 'csv'; #$opt_e = ".$opt_e" unless $opt_e =~ /^\./; @@ -39,6 +39,9 @@ warn "Retreiving directory listing\n" if $opt_v; my $ls_sftp = sftp(); +$ls_sftp->setcwd($opt_r) or die "can't chdir to $opt_r\n" + if $opt_r; + my $ls = $ls_sftp->ls('.', wanted => qr/^$opt_p.*\.$opt_e$/i ); ### @@ -104,7 +107,7 @@ cdr.sftp_and_import - Download CDR files from a remote server via SFTP =head1 SYNOPSIS - cdr.sftp_and_import [ -p prefix ] [ -e extension ] [ -d donefolder ] [ -v ] user format [sftpuser@]servername + cdr.sftp_and_import [ -p prefix ] [ -e extension ] [ -r remotefolder ] [ -d donefolder ] [ -v ] user format [sftpuser@]servername =head1 DESCRIPTION @@ -115,6 +118,8 @@ import them into the database. -e: file extension, defaults to .csv +-r: if specified, changes into this remote folder before starting + -d: if specified, moves files to the specified folder when done -v: verbose -- cgit v1.2.1 From 96c2153a00ebf556d94feaf033ce337c13dd0cc6 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 9 Jul 2009 23:59:34 +0000 Subject: sansay CDRs, RT#5495 --- FS/FS/cdr.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index 418519eb2..8ade4ea41 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -753,6 +753,11 @@ sub _cdr_date_parse { return '' unless length($date); #that's okay, it becomes NULL + if ( $date =~ /^([a-z]{3})\s+([a-z]{3})\s+(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2}\s+(\d{4})$/i && $7 > 1970 ) { + my $time = str2time($date); + return $time if $time > 100000; #just in case + } + my($year, $mon, $day, $hour, $min, $sec); #$date =~ /^\s*(\d{4})[\-\/]\(\d{1,2})[\-\/](\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})\s*$/ -- cgit v1.2.1 From f1f09d882038f5b9950598be62d94fc1486596d3 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 10 Jul 2009 00:00:37 +0000 Subject: sansay CDRs, RT#5495 --- FS/FS/cdr.pm | 2 +- FS/FS/cdr/sansay.pm | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++ eg/cdr_template.pm | 3 +- 3 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 FS/FS/cdr/sansay.pm diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index 8ade4ea41..77f3ec6dc 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -753,7 +753,7 @@ sub _cdr_date_parse { return '' unless length($date); #that's okay, it becomes NULL - if ( $date =~ /^([a-z]{3})\s+([a-z]{3})\s+(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2}\s+(\d{4})$/i && $7 > 1970 ) { + if ( $date =~ /^([a-z]{3})\s+([a-z]{3})\s+(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})\s+(\d{4})$/i && $7 > 1970 ) { my $time = str2time($date); return $time if $time > 100000; #just in case } diff --git a/FS/FS/cdr/sansay.pm b/FS/FS/cdr/sansay.pm new file mode 100644 index 000000000..44accdce5 --- /dev/null +++ b/FS/FS/cdr/sansay.pm @@ -0,0 +1,408 @@ +package FS::cdr::sansay; + +use strict; +use base qw( FS::cdr ); +use vars qw( %info ); +use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker ); + +%info = ( + 'name' => 'Sansay VSX', + 'weight' => 135, + 'header' => 1, #0 default, set to 1 to ignore the first line, or + # to higher numbers to ignore that number of lines + 'type' => 'csv', #csv (default), fixedlength or xls + 'sep_char' => ';', #for csv, defaults to , + 'disabled' => 0, #0 default, set to 1 to disable + + + #listref of what to do with each field from the CDR, in order + 'import_fields' => [ + + # "Header" (I do not think this means what you think it means) + #002452502;V1.10;R; + + # Record Sequence Number 9 Unique identification of this record + 'uniqueid', + + '', #Version Number 5 Format version number of records to follow + # "V1.10" + '', #Record Type 1 Type of CDR being generated + # R ­ Normal CDR record, A - Audit + + # "Body" + #WithMedia;181-1071459514@192.188.0.28;0001;Mon Dec 15 11:38:34 2003;Mon Dec 15 11:38:41 2003;Mon Dec 15 11:38:48 2003;480;EndedByRemoteUser;3;T;000200;H323;;192.188.0.38;9001;192.188.0.28;f0faff54-2e6c-11d8-8c4b-bd4d562c2265;192.188.0.38;18044;192.188.0.28;10756;G.729b;240;460;6066;14060;0;0;0;000200;H323;;192.188.0.28;8811;192.188.0.38;e83af3d3-1d2d-d811-9f98-003048424934;192.188.0.38;19236;192.188.0.28;10758;G.729b;460;240;14060;6066;0;0;0;F;9001;305;2;15;305000;00000011 44934567 45231267 2300BCC0;8587542200; + + '', #ConnectionType 16 Type of connection : Media or No Media + '', #SessionID 32 Unique ID assigned to the call by + # SSM subsystem + '', #XXX #Release Cause 4 2.4 Internal process Release Cause + + #Cause Code Descriptions + #01 Normal answered call + #02 No Answer, tear down by originator + #03 No answer, tear down by the termination + #04 NORMAL_NO_ANSWER, tear down by + # system + #402 Service Not Available + #403 Termination capability un-compatible + #404 Outbound digit translation failed + #405 Termination reject for some other reasons + #406 Termination Route is blocked + #500 Originator is not in the Authorized list + # (source verification failed) + #501 Origination digit translation failed + #502 Origination direction is not bi-directional or + # inbound + #503 Origination is not in service state + #600 Max system call handling reached + #601 System reject call + #602 System outbound digit translation error + # (maybe invalid configuration) + #603 System inbound digit translation error + # (Maybe invalid configuration) + + + #Start Time of Date 32 Indicates Time of Date when the call + # entered the system + _cdr_date_parser_maker('startddate'), + + #Answer Time of Date 32 Indicates TOD when the call was + # answered + _cdr_date_parser_maker('answerdate'), + + #Release TOD 32 Indicates the TOD when the call was + # disconnected + _cdr_date_parser_maker('enddate'), + + #Minutes West of 32 Minutes West of Greenwich Mean + #Greenwich Mean Time Time. Used to calculate the time + # zone. + '', #XXX use this + + #Release Cause from 32 Release cause string from either H323 + #Protocol Stack or SIP protocol stack + #4. Release Cause String (Field #8 in CDR) + #- a string of text further identifying the teardown circumstance from terminating protocol message. + '', + + #Binary Value of Release 4 Binary value of the protocol release + #Cause from Protocol cause + #stack + # + #3. Release Cause from Stack ( Field # 9 in CDR) + #- an integer value based on the releasing dialogues protocol. + # a. For a H.323 call leg originated release it will be the real Q.931 value received from the far + # side. + #Some of the Q.931 release causes; + #3: No route to destination + #16; Normal Clearing + #17: User Busy + #19: NO Answer from User + #21; Call Rejected + #28: Address Incomplete + #34: No Circuit Channel Available + #.... + # b. For a SIP call leg originated release, it's a RFC 3261 release cause value received from the + # far side. + #The following is the list that VSX generated if certain event happen: + #"400 Parse Failed" - Malformed Message + #"405 Method Not Allowed" - Unsupported Method + #"480 Temporarily Unavailable" - Overload Throttle Rejection, Max Sessions + #Exceeded, Demo License Expired, Capacity Exceeded on Route, Radius Server Timeout + #"415 No valid codec" - No valid codec could be supported between origination and + #term call legs. + #"481 Transaction Does Not Exist" - Unknown Transaction or Dialog + #"487 Transaction Terminated" - Origination Cancel + #"488 ReInvite Rejected" - Relay of ReInvite was Rejected + #"504 Server Time-out" - Internal VSX Failure + #"500 Sequence Out of Order" - CSeq counter violation + # c. For a VSX system originated release, it an internal release cause for teardown. + #If the VSX initiates a call teardown, the following cause values and strings are written into the CDR: + #999, "Demo Licence Expired!" + #999, "VSX Capacity Exceeded" + #999, "VSX Operator Reset" + #999, "Route Rejected" + #999, "Radius Rejected" + #999, "Radius Access Timeout" + #999, "Gatekeeper Reject" + #999, "Enum Server Reject" + #999, "Enum Server Timeout" + #999, "DNS Server Reject" + #999, "DNS/GK Timeout" + #999, "Could not allocate media" + #999, "No Response to INVITE" + #999, "Ring No Answer Timeout" + #999, "200 OK Timeout" + #999, "Maximum Duration Exceeded" + #987, "Termination Capacity Exceeded" + #987, "Origination Capacity Exceeded" + #987, "Term CPS Capacity Exceeded" + #987, "Orig CPS Capacity Exceeded" + #987, "Max H323 Legs Exceeded" + '', + + #1st release dialogue 1 O: origination, T: termination + #2. 1st Release Dialogue ( Field #10 in CDR) + #- one character value identifying the side of the call that i + # ,,O ­ origination initiated the teardown. + # ,,T ­ termination initiated the teardown. + # ,,N ­ the VSX internally initiated the teardown. + '', + + #Trunk ID -- Origination 6 TrunkID for origination GW(resources) + 'accountcode', # right? # use cdr-charged_party-accountcode + + #VoIP Protocol - Origination 6 VoIP protocol for origination dialogue + '', + + #Origination Source Number 128 Source Number in Origination Dialogue + 'src', + + #Origination Source Host Name 128 FQDN or IP address for Source GW in Origination Dialogue + 'channel', + + #Origination Destination Number 128 Destination Number in Origination + #Dialogue + 'dst', + + #Origination Destination Host Name 128 FQDN or IP address for Destination + #GW in Origination Dialogue + 'dstchannel', + + #Origination Call ID 128 Unique ID for the origination dialogue(leg) + '', #'clid', #? that's not really the same call ID + + #Origination Remote 16 Remote Payload IP address for + # Payload IP origination dialogue + # Address + '', + + #Origination Remote 6 Remote Payload UDP address for + # Payload UDP origination dialogue + # Address + '', + + #Origination Local 16 Local(SG) Payload IP address for + # Payload IP origination dialogue + # Address + '', + + #Origination Local 6 Local(SG) Payload UDP address for + # Payload UDP origination dialogue + # Address + '', + + #Origination Codec List 128 Supported Codec list( separated by + # comma) for origination dialogue + '', + + #Origination Ingress 10 Number of Ingress( into Sansay + # Packets system) payload packets in + # origination dialogue + '', + + #Origination Egress 10 Number of Egress( out from Sansay + # Packets system) payload packets in + # origination dialogue + '', + + #Origination Ingress 10 Number of Ingress( into Sansay + # Octets system) payload octets in origination + # dialogue + '', + + #Origination Egress 10 Number of Egress( out from Sansay + # Octets system) payload octets in origination + # dialogue + '', + + #Origination Ingress 10 Number of Ingress( into Sansay + # Packet Loss system) payload packet loss in + # origination dialogue + '', + + #Origination Ingress 10 Average Ingress( into Sansay system) + # Delay payload packets delay ( in ms) in + # origination dialogue + '', + + #Origination Ingress 10 Average of Ingress( into Sansay + # Packet Jitter system) payload packet Jitter ( in ms) + # in origination dialogue + '', + + #Trunk ID -- Termination 6 Trunk ID for termination GW(resources) + 'carrierid', + + #VoIP Protocol - 6 VoIP protocol from termination GW + # Termination + '', + + #Termination Source 128 Source Number in Termination + # Number Dialogue + '', + + #Termination Source Host 128 FQDN or IP address for Source GW + # Name in Termination Dialogue + '', + + #Termination Destination 128 Destination Number in Termination + # Number Dialogue + '', + + #Termination Destination 128 FQDN or IP address for Destination + # Host Name GW in Termination Dialogue + '', + + #Termination Call ID 128 Unique ID for the termination + # dialogue(leg) + '', + + #Termination Remote 16 Remote Payload IP address for + # Payload IP termination dialogue + # Address + '', + + #Termination Remote 6 Remote Payload UDP address for + # Payload UDP termination dialogue + # Address + '', + + #Termination Local 16 Local(SG) Payload IP address for + # Payload IP termination dialogue + # Address + '', + + #Termination Local 6 Local(SG) Payload UDP address for + # Payload UDP termination dialogue + # Address + '', + + #Termination Codec List 128 Supported Codec list( separated by + # comma) for termination dialogue + '', + + #Termination Ingress 10 Number of Ingress( into Sansay + # Packets system) payload packets in + # termination dialogue + '', + + #Termination Egress 10 Number of Egress( out from Sansay + # Packets system) payload packets in + # termination dialogue + '', + + #Termination Ingress 10 Number of Ingress( into Sansay + # Octets system) payload octets in + # termination dialogue + '', + + #Termination Egress 10 Number of Egress( out from Sansay + # Octets system) payload octets in + # termination dialogue + '', + + #Termination Ingress 10 Number of Ingress( into Sansay + # Packet Loss system) payload packet loss in + # termination dialogue + '', + + #Termination Ingress 10 Average Ingress( into Sansay system) + # Delay payload packets delay ( in ms) in + # termination dialogue + '', + + #Termination Ingress 10 Average of Ingress( into Sansay + # Packet Jitter system) payload packet Jitter ( in ms) + # in termination dialogue + '', + + #Final Route Indication 1 F: Final Route Selection, + # I: Intermediate Route Attempts + '', + + #Routing Digits 64 Routing Digit (Digit after Inbound + # translation, before Outbound + # Translation). This may also be the + # LRN if LNP feature is enabled + '', + + #Call Duration in Second 6 Call Duration in Seconds. 0 if this is + # failed call + 'billsec', + + #Post Dial Delay in 6 Post dial delay (from call attempt to + # Seconds ring). 0 if this is failed call + '', + + #Ring Time in Second 6 Ring Time in Seconds. 0 if this is + # failed call + '', + + #Duration in milliseconds 10 Call duration in milliseconds. + '', + + #Conf ID 36 Unique Conference ID for this call in + # Cisco format + '', + + #RPID/ANI 32 Inbound Remote Party ID line or + # Proxy Asserted Identity if provided + 'clid', #? + + ], + +); + +1; + +__END__ + +list of freeside CDR fields, useful ones marked with * + +N/A acctid - primary key +FILLED_IN *[1] calldate - Call timestamp (SQL timestamp) +DONE clid - Caller*ID with text +DONE * src - Caller*ID number / Source number +DONE * dst - Destination extension + dcontext - Destination context +DONE channel - Channel used +DONE dstchannel - Destination channel if appropriate + lastapp - Last application if appropriate + lastdata - Last application data +DONE * startdate - Start of call (UNIX-style integer timestamp) +DONE answerdate - Answer time of call (UNIX-style integer timestamp) +DONE * enddate - End time of call (UNIX-style integer timestamp) +* duration - Total time in system, in seconds +DONE * billsec - Total time call is up, in seconds +*[2] disposition - What happened to the call: ANSWERED, NO ANSWER, BUSY + amaflags - What flags to use: BILL, IGNORE etc, specified on a per + channel basis like accountcode. +DONE *[3] accountcode - CDR account number to use: account + uniqueid - Unique channel identifier + userfield - CDR user-defined field + cdr_type - CDR type - see FS::cdr_type (Usage = 1, S&E = 7, OC&C = 8) +FILLED_IN *[4] charged_party - Service number to be billed + upstream_currency - Wholesale currency from upstream +*[5] upstream_price - Wholesale price from upstream + upstream_rateplanid - Upstream rate plan ID + rated_price - Rated (or re-rated) price + distance - km (need units field?) + islocal - Local - 1, Non Local = 0 +*[6] calltypenum - Type of call - see FS::cdr_calltype + description - Description (cdr_type 7&8 only) (used for + cust_bill_pkg.itemdesc) + quantity - Number of items (cdr_type 7&8 only) +DONE carrierid - Upstream Carrier ID (see FS::cdr_carrier) + upstream_rateid - Upstream Rate ID + svcnum - Link to customer service (see FS::cust_svc) + freesidestatus - NULL, done (or something) + +[1] Auto-populated from startdate if not present +[2] Package options available to ignore calls without a specific disposition +[3] When using 'cdr-charged_party-accountcode' config +[4] Auto-populated from src (normal calls) or dst (toll free calls) if not present +[5] When using 'upstream_simple' rating method. +[6] Set to usage class classnum when using pre-rated CDRs and usage class-based + taxation (local/intrastate/interstate/international) + diff --git a/eg/cdr_template.pm b/eg/cdr_template.pm index 5499d2267..31ccedff4 100644 --- a/eg/cdr_template.pm +++ b/eg/cdr_template.pm @@ -29,6 +29,7 @@ use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker ); #premade subref factory for date+time parsing, understands dates like: # 10/31/2007 08:57:24 # 2007-10-31 08:57:24.113000000 + # Mon Dec 15 11:38:34 2003 _cdr_date_parser_maker('startddate'), #for example #premade subref factory for decimal minute parsing @@ -71,7 +72,7 @@ list of freeside CDR fields, useful ones marked with * amaflags - What flags to use: BILL, IGNORE etc, specified on a per channel basis like accountcode. *[3] accountcode - CDR account number to use: account - uniqueid - Unique channel identifier (Unitel/RSLCOM Event ID) + uniqueid - Unique channel identifier userfield - CDR user-defined field cdr_type - CDR type - see FS::cdr_type (Usage = 1, S&E = 7, OC&C = 8) *[4] charged_party - Service number to be billed -- cgit v1.2.1 From be5a76006fb0d317c667c0432737284146b2ae45 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 10 Jul 2009 00:36:02 +0000 Subject: fix sansay CDR import to ignore "NA" in dates, RT#5495 --- FS/FS/cdr.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index 77f3ec6dc..723123a76 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -752,6 +752,7 @@ sub _cdr_date_parse { my %options = @_; return '' unless length($date); #that's okay, it becomes NULL + return '' if $date eq 'NA'; #sansay if ( $date =~ /^([a-z]{3})\s+([a-z]{3})\s+(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})\s+(\d{4})$/i && $7 > 1970 ) { my $time = str2time($date); -- cgit v1.2.1 From 33d0ac01c47763fdc394c2b477c7e8aadbbe4156 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 10 Jul 2009 17:50:26 +0000 Subject: fix svc_phone provisioning! --- httemplate/elements/select-did.html | 4 +++- httemplate/elements/tr-select-did.html | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/httemplate/elements/select-did.html b/httemplate/elements/select-did.html index 2ff583ee1..af8d59513 100644 --- a/httemplate/elements/select-did.html +++ b/httemplate/elements/select-did.html @@ -70,7 +70,9 @@ my $country = $conf->config('countrydefault') || 'US'; #false laziness w/tr-select-did.html #XXX make sure this comes through on errors too -my $svcpart = $opt{'svcpart'} || $opt{'object'}->cust_svc->svcpart; +my $svcpart = $opt{'svcpart'} + || $opt{'object'}->svcpart + || $opt{'object'}->cust_svc->svcpart; my $part_svc = qsearchs('part_svc', { 'svcpart'=>$svcpart } ); die "unknown svcpart $svcpart" unless $part_svc; diff --git a/httemplate/elements/tr-select-did.html b/httemplate/elements/tr-select-did.html index 6dd057600..e866d0d7e 100644 --- a/httemplate/elements/tr-select-did.html +++ b/httemplate/elements/tr-select-did.html @@ -24,7 +24,9 @@ my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : ''; #false laziness w/select-did.html #XXX make sure this comes through on errors too -my $svcpart = $opt{'svcpart'} || $opt{'object'}->cust_svc->svcpart; +my $svcpart = $opt{'svcpart'} + || $opt{'object'}->svcpart + || $opt{'object'}->cust_svc->svcpart; my $part_svc = qsearchs('part_svc', { 'svcpart'=>$svcpart } ); die "unknown svcpart $svcpart" unless $part_svc; -- cgit v1.2.1 From 0457702b06344646733df138e8df351fadd7ea3e Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 11 Jul 2009 02:40:45 +0000 Subject: notes --- bin/drop_slony.slonik | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 bin/drop_slony.slonik diff --git a/bin/drop_slony.slonik b/bin/drop_slony.slonik new file mode 100644 index 000000000..04ffaca7c --- /dev/null +++ b/bin/drop_slony.slonik @@ -0,0 +1,9 @@ +cluster name = freeside; + +node 1 admin conninfo = 'dbname=freeside host=XXX user=postgres'; +node 2 admin conninfo = 'dbname=freeside host=XXX user=postgres'; + +drop set (id=1, origin=1); + +uninstall node ( id=1 ); + -- cgit v1.2.1 From 27af526f59996d1f1cb8f4181d4e320020c98062 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 12 Jul 2009 13:27:07 +0000 Subject: stop gratuitous hash manipulatoin during enum untaint --- FS/FS/Record.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 3e3af524c..be29b5c8a 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -2342,7 +2342,7 @@ sub ut_enum { my( $self, $field, $choices ) = @_; foreach my $choice ( @$choices ) { if ( $self->getfield($field) eq $choice ) { - $self->setfield($choice); + $self->setfield($field, $choice); return ''; } } -- cgit v1.2.1 From 8517a04eae51c3964f88bf4b72211ff4a763d8b0 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 12 Jul 2009 19:32:18 +0000 Subject: update tickting config descriptions --- httemplate/elements/menu.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 48b7c498e..a24af7b37 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -371,11 +371,11 @@ if ( $curuser->access_right('Configuration') ) { tie my %config_ticketing, 'Tie::IxHash', 'Ticketing Users' => [ $fsurl.'rt/Admin/Users', 'View/Edit ticketing users' ], #XXX to be unified - 'Ticketing Groups' => [ $fsurl.'rt/Admin/Groups', 'View/Edit ticketing groups' ], #XXX to be unified - 'Ticketing Queues' => [ $fsurl.'rt/Admin/Queues', '' ], - 'Ticket Custom Fields' => [ $fsurl.'rt/Admin/CustomFields', '' ], - 'Ticketing Global' => [ $fsurl.'rt/Admin/Global', 'Global ticketing configuration' ], - #'Ticketing Tools' => [ $fsurl.'rt/Admin/Tools', '' ], + 'Ticketing Groups' => [ $fsurl.'rt/Admin/Groups', 'View/Edit ticketing groups and group membership' ], #XXX to be unified + 'Ticketing Queues' => [ $fsurl.'rt/Admin/Queues', 'View/Edit ticketing queues and queue-specific properties' ], + 'Ticket Custom Fields' => [ $fsurl.'rt/Admin/CustomFields', 'View/Edit ticketing custom fields' ], + 'Ticketing Global' => [ $fsurl.'rt/Admin/Global', 'View/Edit ticketing configuration applicable to all queues' ], + #"System Configuraiton"? useless, just makes people report errors about missing Module::Versions::Report #'Ticketing Tools' => [ $fsurl.'rt/Admin/Tools', '' ], ; tie my %config_dialup, 'Tie::IxHash', -- cgit v1.2.1 From a404926bbec025159de0611ce95783488a8bd241 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 12 Jul 2009 23:22:06 +0000 Subject: resolve style weirdness (fallout from RT integration), especially non-fixed-width comment boxes, menu/searchbar differences, RT#1169 --- httemplate/elements/header.html | 89 +++++++++++++++++++---------- httemplate/elements/menu.html | 6 +- httemplate/elements/xmenu.css | 2 + httemplate/elements/xmenu.top.css | 2 + rt/FREESIDE_MODIFIED | 3 + rt/etc/RT_SiteConfig.pm | 2 + rt/html/Elements/Header | 3 +- rt/html/NoAuth/css/3.5-default/freeside.css | 75 +----------------------- rt/html/NoAuth/css/3.5-default/misc.css | 5 +- rt/html/Ticket/Display.html | 4 +- 10 files changed, 82 insertions(+), 109 deletions(-) diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html index 0bbd4fd8c..9d062cf9a 100644 --- a/httemplate/elements/header.html +++ b/httemplate/elements/header.html @@ -10,6 +10,7 @@ <% include('menu.html', 'freeside_baseurl' => $fsurl, 'position' => $menu_position, + 'nocss' => $nocss, ) |n %> @@ -17,7 +18,7 @@ + + Click on add states to specify a country's tax rates by state or province. +
Click on add counties to specify a state's tax rates by county, or remove counties to remove per-county tax rates. +END + $html_init .= "
Click on separate taxclasses to specify taxes per taxclass." if $enable_taxclasses; $html_init .= '

'; @@ -360,11 +378,16 @@ my @fields = ( ) ) }, - sub { $_[0]->county || '(all) '. - expand_link( desc => 'Add Counties', - row => $_[0], - label => 'add counties', - ) + sub { $_[0]->county + ? $_[0]->county. ' '. + collapse_link( label=> 'remove counties', + row => $_[0], + ) + : '(all) '. + expand_link( desc => 'Add Counties', + row => $_[0], + label => 'add counties', + ); }, ); diff --git a/httemplate/edit/process/cust_main_county-collapse.cgi b/httemplate/edit/process/cust_main_county-collapse.cgi index a917825ce..18bd1fde2 100755 --- a/httemplate/edit/process/cust_main_county-collapse.cgi +++ b/httemplate/edit/process/cust_main_county-collapse.cgi @@ -1,44 +1,37 @@ -% -% -%my($query) = $cgi->keywords; -%$query =~ /^(\d+)$/ or die "Illegal taxnum!"; -%my $taxnum = $1; -%my $cust_main_county = qsearchs('cust_main_county', { 'taxnum' => $taxnum } ) -% or die "Unknown taxnum $taxnum"; -% -%#really should do this in a .pm & start transaction -% -%foreach my $delete ( qsearch('cust_main_county', { -% 'country' => $cust_main_county->country, -% 'state' => $cust_main_county->state -% } ) ) { -%# unless ( qsearch('cust_main',{ -%# 'state' => $cust_main_county->getfield('state'), -%# 'county' => $cust_main_county->getfield('county'), -%# 'country' => $cust_main_county->getfield('country'), -%# } ) ) { -% my $error = $delete->delete; -% die $error if $error; -%# } else { -% #should really fix the $cust_main record -%# } -% -%} -% -%$cust_main_county->taxnum(''); -%$cust_main_county->county(''); -%my $error = $cust_main_county->insert; -%die $error if $error; -% -%print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi"); -% -% +<% $cgi->redirect(popurl(3). "browse/cust_main_county.cgi") %> <%init> -#this isn't actually linked from anywhere just now, but it will be again soon - die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ or die "Illegal taxnum!"; +my $taxnum = $1; +my $cust_main_county = qsearchs('cust_main_county', { 'taxnum' => $taxnum } ) + or die "Unknown taxnum $taxnum"; + +#really should do this in a .pm & start transaction + +foreach my $delete ( qsearch('cust_main_county', { + 'country' => $cust_main_county->country, + 'state' => $cust_main_county->state + } ) ) { +# unless ( qsearch('cust_main',{ +# 'state' => $cust_main_county->getfield('state'), +# 'county' => $cust_main_county->getfield('county'), +# 'country' => $cust_main_county->getfield('country'), +# } ) ) { + my $error = $delete->delete; + die $error if $error; +# } else { + #should really fix the $cust_main record +# } + +} + +$cust_main_county->taxnum(''); +$cust_main_county->county(''); +my $error = $cust_main_county->insert; +die $error if $error; -- cgit v1.2.1 From 695ac96e964ecfb14ddcac0f138e50219dedf4e2 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 23 Jul 2009 16:48:55 +0000 Subject: restore svc_acct_pop editing --- httemplate/browse/svc_acct_pop.cgi | 1 + 1 file changed, 1 insertion(+) diff --git a/httemplate/browse/svc_acct_pop.cgi b/httemplate/browse/svc_acct_pop.cgi index c6e615d40..501d3625a 100755 --- a/httemplate/browse/svc_acct_pop.cgi +++ b/httemplate/browse/svc_acct_pop.cgi @@ -23,6 +23,7 @@ $num_accounts_sub, ], 'align' => 'rllrrrr', + 'links' => [ map { $svc_acct_pop_link } (1..6) ], ) %> <%init> -- cgit v1.2.1 From 6fcc07e1f7e5ef310413967b9eb32f57e30c60ae Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 23 Jul 2009 19:40:28 +0000 Subject: fix -r option, RT#5675 --- FS/bin/freeside-void-payments | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/bin/freeside-void-payments b/FS/bin/freeside-void-payments index 18fed05a7..b6869a342 100755 --- a/FS/bin/freeside-void-payments +++ b/FS/bin/freeside-void-payments @@ -14,7 +14,7 @@ use Date::Parse 'str2time'; use Date::Format 'time2str'; my %opt; -getopts("f:ca:g:s:e:", \%opt); +getopts("r:f:ca:g:s:e:", \%opt); $user = shift or die &usage; &adminsuidsetup( $user ); -- cgit v1.2.1 From 0580d615b6339dc2e3cba1700d689074aca7d78d Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 23 Jul 2009 19:46:05 +0000 Subject: avoid harmless warning: Use of uninitialized value in string ne --- FS/FS/cust_pay.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 201b427aa..4ff291934 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -345,7 +345,8 @@ sub delete { return $error; } - if ( $conf->config('deletepayments') ne '' ) { + if ( $conf->exists('deletepayments') + && $conf->config('deletepayments') ne '' ) { my $cust_main = $self->cust_main; -- cgit v1.2.1 From 68f56930178c09ee08d2ab4045298d0cb1757ce8 Mon Sep 17 00:00:00 2001 From: mark Date: Fri, 24 Jul 2009 05:51:19 +0000 Subject: Add -v switch (verbose) to freeside-void-payments --- FS/bin/freeside-void-payments | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/FS/bin/freeside-void-payments b/FS/bin/freeside-void-payments index b6869a342..9aa04d671 100755 --- a/FS/bin/freeside-void-payments +++ b/FS/bin/freeside-void-payments @@ -8,13 +8,14 @@ use FS::Record qw(qsearchs); use FS::Conf; use FS::cust_main; use FS::cust_pay; +use FS::cust_pay_void; use Business::OnlinePayment; # For retrieving the void list only. use Time::Local; use Date::Parse 'str2time'; use Date::Format 'time2str'; my %opt; -getopts("r:f:ca:g:s:e:", \%opt); +getopts("r:f:ca:g:s:e:vn", \%opt); $user = shift or die &usage; &adminsuidsetup( $user ); @@ -80,20 +81,41 @@ else { } $opt{'r'} ||= 'freeside-void-payments'; - +my $success = 0; +my $notfound = 0; +print "Voiding ".scalar(@auths)." transactions:\n" if $opt{'v'}; foreach my $authnum (@auths) { my $paybatch = $gatewaynum . $processor . ':' . $authnum; my $cust_pay = qsearchs('cust_pay', { paybatch => $paybatch } ); + my $error; if($cust_pay) { - $cust_pay->void($opt{'r'}); + $error = $cust_pay->void($opt{'r'}); + $success++ if not $error; } else { - warn "cust_pay record not found: '$paybatch'"; + my $cpv = qsearchs('cust_pay_void', { paybatch => $paybatch }); + if($cpv) { + $error = 'already voided '.time2str('%Y-%m-%d', $cpv->void_date) . + ' by ' . $cpv->otaker; + } + else { + $error = 'not found'; + $notfound++; + } + } + if($opt{'v'}) { + print $authnum; + print "\t($error)" if $error; + print "\n"; } } +if($opt{'v'}) { + print scalar(@auths)." transactions: $success voided, $notfound not found\n"; +} + sub usage { - die "Usage:\n\n freeside-void-payments [ -f file | [ -s start-date ] [ -e end-date ] ] [ -r 'reason' ] [ -g gatewaynum | -a agentnum ] [ -c ] user\n"; + die "Usage:\n\n freeside-void-payments [ -f file | [ -s start-date ] [ -e end-date ] ] [ -r 'reason' ] [ -g gatewaynum | -a agentnum ] [ -c ] [ -v ] [ -n ]user\n"; } __END__ @@ -106,7 +128,7 @@ freeside-void-payments - Automatically void a list of returned payments. =head1 SYNOPSIS - freeside-void-payments [ -f file | [ -s start-date ] [ -e end-date ] ] [ -r 'reason' ] [ -g gatewaynum | -a agentnum ] [ -c ] user + freeside-void-payments [ -f file | [ -s start-date ] [ -e end-date ] ] [ -r 'reason' ] [ -g gatewaynum | -a agentnum ] [ -c ] [ -v ] [ -n ] user =head1 DESCRIPTION @@ -145,6 +167,8 @@ generally how the processor will identify them later. -c: Use the default gateway for check transactions rather than credit cards. + -v: Be verbose. + A warning will be emitted for each transaction that can't be found. This may happen if it's already been voided, or if the gateway doesn't match. -- cgit v1.2.1 From f0edb7c4423b58ad3659e0069f1f69b2e9b11021 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 24 Jul 2009 09:38:15 +0000 Subject: add handling of ChilliSpot (and CoovaChilli) Max attributes, specifically ChilliSpot-Max-{Input,Output,Total}-{Octets,Gigawords}, RT#5815 --- FS/FS/Conf.pm | 8 ++++++++ FS/FS/svc_acct.pm | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 8ae926e6b..832322faf 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1664,6 +1664,14 @@ worry that config_items is freeside-specific and icky. 'select_enum' => [ 'Framed-IP-Address', 'Framed-Address' ], }, + #http://dev.coova.org/svn/coova-chilli/doc/dictionary.chillispot + { + 'key' => 'radius-chillispot-max', + 'section' => '', + 'description' => 'Enable ChilliSpot (and CoovaChilli) Max attributes, specifically ChilliSpot-Max-{Input,Output,Total}-{Octets,Gigawords}.', + 'type' => 'checkbox', + }, + { 'key' => 'svc_acct-alldomains', 'section' => '', diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 4669588d5..6f61eae0e 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -15,6 +15,7 @@ use vars qw( @ISA $DEBUG $me $conf $skip_fuzzyfiles $dirhash @saltset @pw_set ); use Scalar::Util qw( blessed ); +use Math::BigInt; use Carp; use Fcntl qw(:flock); use Date::Format; @@ -1440,6 +1441,28 @@ sub radius_reply { $reply{'Session-Timeout'} = $self->seconds; } + if ( $conf->exists('radius-chillispot-max') ) { + #http://dev.coova.org/svn/coova-chilli/doc/dictionary.chillispot + + #hmm. just because sqlradius.pm says so? + my %whatis = ( + 'input' => 'up', + 'output' => 'down', + 'total' => 'total', + ); + + foreach my $what (qw( input output total )) { + my $is = $whatis{$what}.'bytes'; + if ( $self->$is() =~ /\d/ ) { + my $big = new Math::BigInt $self->$is(); + my $att = "Chillispot-Max-\u$what"; + $reply{"$att-Octets"} = $big->copy->band(0xffffffff)->bstr; + $reply{"$att-Gigawords"} = $big->copy->brsft(32)->bstr; + } + } + + } + %reply; } @@ -1772,6 +1795,16 @@ sub _op_usage { die "Can't update $column for svcnum". $self->svcnum if $rv == 0; + #$self->snapshot; #not necessary, we retain the old values + #create an object with the updated usage values + my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum }); + #call exports + my $error = $new->replace($self); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error replacing: $error"; + } + #overlimit_action eq 'cancel' handling my $cust_pkg = $self->cust_svc->cust_pkg; if ( $cust_pkg @@ -1925,6 +1958,16 @@ sub set_usage { if $rv == 0; } + #$self->snapshot; #not necessary, we retain the old values + #create an object with the updated usage values + my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum }); + #call exports + my $error = $new->replace($self); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error replacing: $error"; + } + if ( $reset ) { my $error; @@ -2706,6 +2749,8 @@ probably live somewhere else... insertion of RADIUS group stuff in insert could be done with child_objects now (would probably clean up export of them too) +_op_usage and set_usage bypass the history... maybe they shouldn't + =head1 SEE ALSO L, edit/part_svc.cgi from an installed web interface, -- cgit v1.2.1 From a1937e6377a16bd90f345b77a1cab3ebfbe1a2b1 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 25 Jul 2009 07:57:14 +0000 Subject: teach Record.pm about BYTEA handling in order to store files in the db, RT#4964 --- FS/FS/Record.pm | 81 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index be29b5c8a..9e1c0e890 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -54,6 +54,12 @@ FS::UID->install_callback( sub { $conf = FS::Conf->new; $conf_encryption = $conf->exists('encryption'); $File::CounterFile::DEFAULT_DIR = $conf->base_dir . "/counters.". datasrc; + if ( driver_name eq 'Pg' ) { + eval "use DBD::Pg qw(:pg_types);"; + die $@ if $@; + } else { + eval "sub PG_BYTEA { die 'guru meditation #9: calling PG_BYTEA when not running Pg?'; }"; + } } ); @@ -252,8 +258,40 @@ fine in the common case where there are only two parameters: my %TYPE = (); #for debugging +sub _bind_type { + my($type, $value) = @_; + + my $bind_type = { TYPE => SQL_VARCHAR }; + + if ( $type =~ /(big)?(int|serial)/i && $value =~ /^\d+(\.\d+)?$/ ) { + + $bind_type = { TYPE => SQL_INTEGER }; + + } elsif ( $type =~ /^bytea$/i || $type =~ /(blob|varbinary)/i ) { + + if ( driver_name eq 'Pg' ) { + no strict 'subs'; + $bind_type = { pg_type => PG_BYTEA }; + #} else { + # $bind_type = ? #SQL_VARCHAR could be fine? + } + + #DBD::Pg 1.49: Cannot bind ... unknown sql_type 6 with SQL_FLOAT + #fixed by DBD::Pg 2.11.8 + #can change back to SQL_FLOAT in early-mid 2010, once everyone's upgraded + #(make a Tron test first) + } elsif ( _is_fs_float( $type, $value ) ) { + + $bind_type = { TYPE => SQL_DECIMAL }; + + } + + $bind_type; + +} + sub _is_fs_float { - my ($type, $value) = @_; + my($type, $value) = @_; if ( ( $type =~ /(numeric)/i && $value =~ /^[+-]?\d+(\.\d+)?$/ ) || ( $type =~ /(real|float4)/i && $value =~ /[-+]?\d*\.?\d+([eE][-+]?\d+)?/) ) { @@ -331,23 +369,14 @@ sub qsearch { $value = $value->{'value'} if ref($value); my $type = dbdef->table($table)->column($field)->type; - my $TYPE = SQL_VARCHAR; - if ( $type =~ /(big)?(int|serial)/i && $value =~ /^\d+(\.\d+)?$/ ) { - $TYPE = SQL_INTEGER; - - #DBD::Pg 1.49: Cannot bind ... unknown sql_type 6 with SQL_FLOAT - #fixed by DBD::Pg 2.11.8 - #can change back to SQL_FLOAT in early-mid 2010, once everyone's upgraded - } elsif ( _is_fs_float( $type, $value ) ) { - $TYPE = SQL_DECIMAL; - } + my $bind_type = _bind_type($type, $value); - if ( $DEBUG > 2 ) { - no strict 'refs'; - %TYPE = map { &{"DBI::$_"}() => $_ } @{ $DBI::EXPORT_TAGS{sql_types} } - unless keys %TYPE; - warn " bind_param $bind (for field $field), $value, TYPE $TYPE{$TYPE}\n"; - } + #if ( $DEBUG > 2 ) { + # no strict 'refs'; + # %TYPE = map { &{"DBI::$_"}() => $_ } @{ $DBI::EXPORT_TAGS{sql_types} } + # unless keys %TYPE; + # warn " bind_param $bind (for field $field), $value, TYPE $TYPE{$TYPE}\n"; + #} #if this needs to be re-enabled, it needs to use a custom op like #"APPROX=" or something (better name?, not '=', to avoid affecting other @@ -357,22 +386,20 @@ sub qsearch { # $sth->bind_param($bind++, $value*1.00001, { TYPE => $TYPE } ); # $sth->bind_param($bind++, $value*.99999, { TYPE => $TYPE } ); #} else { - $sth->bind_param($bind++, $value, { TYPE => $TYPE } ); + $sth->bind_param($bind++, $value, $bind_type ); #} } foreach my $param ( @$extra_param ) { - my $TYPE = SQL_VARCHAR; + my $bind_type = { TYPE => SQL_VARCHAR }; my $value = $param; if ( ref($param) ) { $value = $param->[0]; my $type = $param->[1]; - if ( $type =~ /(big)?(int|serial)/i && $value =~ /^\d+(\.\d+)?$/ ) { - $TYPE = SQL_INTEGER; - } # & DECIMAL? well, who cares for now + $bind_type = _bind_type($type, $value); } - $sth->bind_param($bind++, $value, { TYPE => $TYPE } ); + $sth->bind_param($bind++, $value, $bind_type ); } # $sth->execute( map $record->{$_}, @@ -2678,7 +2705,7 @@ sub _quote { ")\n" if $DEBUG > 2; if ( $value eq '' && $nullable ) { - 'NULL' + 'NULL'; } elsif ( $value eq '' && $column_type =~ /^(int|numeric)/ ) { cluck "WARNING: Attempting to set non-null integer $table.$column null; ". "using 0 instead"; @@ -2686,6 +2713,12 @@ sub _quote { } elsif ( $value =~ /^\d+(\.\d+)?$/ && ! $column_type =~ /(char|binary|text)$/i ) { $value; + } elsif (( $column_type =~ /^bytea$/i || $column_type =~ /(blob|varbinary)/i ) + && driver_name eq 'Pg' + ) + { + no strict 'subs'; + dbh->quote($value, PG_BYTEA); } else { dbh->quote($value); } -- cgit v1.2.1 From d57a1feb48c55fecb95502e894575eebb306a58a Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 25 Jul 2009 21:33:09 +0000 Subject: this should fix the re-email/print links on event search pages sending too much, RT#5740, RT#5570 --- FS/FS/cust_event.pm | 133 ++++++++++++++++++++++++++++++++------ httemplate/search/cust_event.html | 69 +++++--------------- 2 files changed, 132 insertions(+), 70 deletions(-) diff --git a/FS/FS/cust_event.pm b/FS/FS/cust_event.pm index 6df2faaa1..10fb0acf7 100644 --- a/FS/FS/cust_event.pm +++ b/FS/FS/cust_event.pm @@ -1,7 +1,7 @@ package FS::cust_event; use strict; -use vars qw( @ISA $DEBUG ); +use vars qw( @ISA $DEBUG $me ); use Carp qw( croak confess ); use FS::Record qw( qsearch qsearchs dbdef ); use FS::cust_main_Mixin; @@ -14,6 +14,7 @@ use FS::cust_bill; @ISA = qw(FS::cust_main_Mixin FS::Record); $DEBUG = 0; +$me = '[FS::cust_event]'; =head1 NAME @@ -295,6 +296,100 @@ sub retriable { $self->replace($old); } +=item join_cust_sql + +=cut + +sub join_sql { + #my $class = shift; + + " + JOIN part_event USING ( eventpart ) + LEFT JOIN cust_bill ON ( eventtable = 'cust_bill' AND tablenum = invnum ) + LEFT JOIN cust_pkg ON ( eventtable = 'cust_pkg' AND tablenum = pkgnum ) + LEFT JOIN cust_main ON ( ( eventtable = 'cust_main' AND tablenum = cust_main.custnum ) + OR ( eventtable = 'cust_bill' AND cust_bill.custnum = cust_main.custnum ) + OR ( eventtable = 'cust_pkg' AND cust_pkg.custnum = cust_main.custnum ) + ) + "; + +} + +=item search_sql HASHREF + +Class method which returns an SQL WHERE fragment to search for parameters +specified in HASHREF. Valid parameters are + +=over 4 + +=item + +=item + +=back + +=cut + +#Note: validates all passed-in data; i.e. safe to use with unchecked CGI params. +#sub + +sub search_sql { + my($class, $param) = @_; + if ( $DEBUG ) { + warn "$me search_sql called with params: \n". + join("\n", map { " $_: ". $param->{$_} } keys %$param ). "\n"; + } + + my @search = (); + + if ( $param->{'agentnum'} && $param->{'agentnum'} =~ /^(\d+)$/ ) { + push @search, "cust_main.agentnum = $1"; + #my $agent = qsearchs('agent', { 'agentnum' => $1 } ); + #die "unknown agentnum $1" unless $agent; + } + + if ( $param->{'beginning'} =~ /^(\d+)$/ ) { + push @search, "cust_event._date >= $1"; + } + if ( $param->{'ending'} =~ /^(\d+)$/ ) { + push @search, "cust_event._date <= $1"; + } + + if ( $param->{'failed'} ) { + push @search, "statustext != ''", + "statustext IS NOT NULL", + "statustext != 'N/A'"; + } + + #if ( $param->{'part_event.payby'} =~ /^(\w+)$/ ) { + # push @search, "part_event.payby = '$1'"; + #} + + if ( $param->{'custnum'} =~ /^(\d+)$/ ) { + push @search, "cust_main.custnum = '$1'"; + } + + if ( $param->{'invnum'} =~ /^(\d+)$/ ) { + push @search, "part_event.eventtable = 'cust_bill'", + "tablenum = '$1'"; + } + + if ( $param->{'pkgnum'} =~ /^(\d+)$/ ) { + push @search, "part_event.eventtable = 'cust_pkg'", + "tablenum = '$1'"; + } + + #here is the agent virtualization + push @search, + $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' ); + + my $where = 'WHERE '. join(' AND ', @search ); + + + join(' AND ', @search ); + +} + =back =head1 SUBROUTINES @@ -336,41 +431,43 @@ sub process_re_X { re_X( $method, - $param->{'beginning'}, - $param->{'ending'}, - $param->{'failed'}, + $param, $job, ); } -#this needs some updating based on the 1.7 cust_bill_event.pm still, i think sub re_X { - my($method, $beginning, $ending, $failed, $job) = @_; + my($method, $param, $job) = @_; + + my $search_sql = FS::cust_event->search_sql($param); - my $from = 'LEFT JOIN part_event USING ( eventpart )'; + #maybe not...? we do want the "re-" action to match the search more closely + # # yuck! hardcoded *AND* sequential scans! + #my $where = " WHERE action LIKE 'cust_bill_send%' ". + # ( $search_sql ? " AND $search_sql" : "" ); - # yuck! hardcoded *AND* sequential scans! - my $where = " WHERE action LIKE 'cust_bill_send%'". - " AND cust_event._date >= $beginning". - " AND cust_event._date <= $ending"; - $where .= " AND statustext != '' AND statustext IS NOT NULL" - if $failed; + my $where = ( $search_sql ? " WHERE $search_sql" : "" ); my @cust_event = qsearch({ 'table' => 'cust_event', - 'addl_from' => $from, + 'addl_from' => FS::cust_event->join_sql(), 'hashref' => {}, 'extra_sql' => $where, }); + warn "$me re_X found ". scalar(@cust_event). " events\n" + if $DEBUG; + my( $num, $last, $min_sec ) = (0, time, 5); #progresbar foo foreach my $cust_event ( @cust_event ) { - $cust_event->cust_X->$method( - $cust_event->part_event->templatename - || $cust_event->cust_X->agent_template - ); + my $cust_X = $cust_event->cust_X; # cust_bill + next unless $cust_X->can($method); + + $cust_X->$method( $cust_event->part_event->templatename + || $cust_X->agent_template + ); if ( $job ) { #progressbar foo $num++; diff --git a/httemplate/search/cust_event.html b/httemplate/search/cust_event.html index e8164c280..715d1ca9a 100644 --- a/httemplate/search/cust_event.html +++ b/httemplate/search/cust_event.html @@ -147,61 +147,24 @@ die "access denied" || $cgi->param('invnum') =~ /^(\d+)$/ || $cgi->param('pkgnum') =~ /^(\d+)$/ ); - -my $title = $cgi->param('failed') - ? 'Failed billing events' - : 'Billing events'; +my $title = $cgi->param('failed') ? 'Failed billing events' : 'Billing events'; -my @search = (); +my %search = (); -if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) { - push @search, "cust_main.agentnum = $1"; - #my $agent = qsearchs('agent', { 'agentnum' => $1 } ); - #die "unknown agentnum $1" unless $agent; +my @scalars = qw ( agentnum custnum invnum pkgnum failed ); +for my $param ( @scalars ) { + $search{$param} = scalar( $cgi->param($param) ) + if $cgi->param($param); } my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); -push @search, "cust_event._date >= $beginning", - "cust_event._date <= $ending"; +$search{'beginning'} = $beginning; +$search{'ending'} = $ending; -if ( $cgi->param('failed') ) { - push @search, "statustext != ''", - "statustext IS NOT NULL", - "statustext != 'N/A'"; -} - -#if ( $cgi->param('part_event.payby') =~ /^(\w+)$/ ) { -# push @search, "part_event.payby = '$1'"; -#} - -if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { - push @search, "cust_main.custnum = '$1'"; -} -if ( $cgi->param('invnum') =~ /^(\d+)$/ ) { - push @search, "part_event.eventtable = 'cust_bill'", - "tablenum = '$1'"; -} -if ( $cgi->param('pkgnum') =~ /^(\d+)$/ ) { - push @search, "part_event.eventtable = 'cust_pkg'", - "tablenum = '$1'"; -} - -#here is the agent virtualization -push @search, $curuser->agentnums_sql( 'table' => 'cust_main' ); - -my $where = 'WHERE '. join(' AND ', @search ); +my $where = ' WHERE '. FS::cust_event->search_sql( \%search ); -my $join = " - JOIN part_event USING ( eventpart ) - LEFT JOIN cust_bill ON ( eventtable = 'cust_bill' AND tablenum = invnum ) - LEFT JOIN cust_pkg ON ( eventtable = 'cust_pkg' AND tablenum = pkgnum ) - LEFT JOIN cust_main ON ( ( eventtable = 'cust_main' AND tablenum = cust_main.custnum ) - OR ( eventtable = 'cust_bill' AND cust_bill.custnum = cust_main.custnum ) - OR ( eventtable = 'cust_pkg' AND cust_pkg.custnum = cust_main.custnum ) - ) -"; - #'LEFT JOIN cust_main USING ( custnum ) '; +my $join = FS::cust_event->join_sql(); my $sql_query = { 'table' => 'cust_event', @@ -222,22 +185,24 @@ my $count_sql = "SELECT COUNT(*) FROM cust_event $join $where"; my $conf = new FS::Conf; -my $failed = $cgi->param('failed'); +my @params = ( @scalars, qw( beginning ending ) ); my $html_init = join("\n", map { ( my $action = $_ ) =~ s/_$//; include('/elements/progress-init.html', $_.'form', - [ 'action', 'beginning', 'ending', 'failed' ], + [ 'action', @params ], "../misc/${_}events.cgi", { 'message' => "Invoices re-${action}ed" }, #would be nice to show the number of them, but... $_, #key ), qq!
!, qq!!, #not used though - qq!!, - qq!!, - qq!!, + ( map { my $value = encode_entities( $search{$_} ); + qq(); + } + @params #keys %search + ), qq!! } qw( print_ email_ fax_ ) ). -- cgit v1.2.1 From eda086d0c5c4829e3f29dea030d2b0efb6fecbb0 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 25 Jul 2009 22:00:56 +0000 Subject: set a character encoding for all pages; this should fix problems with diamond question marks even when the server gets an UTF-8 default setting, RT#3094 --- htetc/handler.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htetc/handler.pl b/htetc/handler.pl index 711c32a4b..4ce658685 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -44,7 +44,8 @@ sub handler ###Module::Refresh->refresh;### - $r->content_type('text/html'); + #$r->content_type('text/html; charset=utf-8'); + $r->content_type('text/html; charset=iso-8859-1'); #eorar my $headers = $r->headers_out; -- cgit v1.2.1 From 13a13b2e4bd74bb27b77d9492f5cd6487bfe3a21 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 26 Jul 2009 06:40:01 +0000 Subject: command line tool to apply payments and credits --- FS/bin/freeside-apply_payments_and_credits | 79 ++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 FS/bin/freeside-apply_payments_and_credits diff --git a/FS/bin/freeside-apply_payments_and_credits b/FS/bin/freeside-apply_payments_and_credits new file mode 100755 index 000000000..d789c6c2e --- /dev/null +++ b/FS/bin/freeside-apply_payments_and_credits @@ -0,0 +1,79 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw( $DEBUG ); +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch qsearchs); +use FS::cust_main; +use DBI; + +$DEBUG = 1; + +my $user = shift or die &usage; +my $dbh = adminsuidsetup $user; + +my $unapplied_payments_sql = < + ( ( SELECT coalesce(sum(amount),0) FROM cust_bill_pay + WHERE cust_pay.paynum = cust_bill_pay.paynum ) + + ( SELECT coalesce(sum(amount),0) FROM cust_pay_refund + WHERE cust_pay.paynum = cust_pay_refund.paynum) + ) +EOF + +my $unapplied_credits_sql = < + ( ( SELECT coalesce(sum(cust_credit_bill.amount),0) FROM cust_credit_bill + WHERE cust_credit.crednum = cust_credit_bill.crednum ) + + ( SELECT coalesce(sum(cust_Credit_refund.amount),0) FROM cust_credit_refund + WHERE cust_credit.crednum = cust_credit_refund.crednum) + ) +EOF + +my %custnum = (); + +my $sth = $dbh->prepare($unapplied_payments_sql) or die $dbh->errstr; +$sth->execute or die "unapplied payment search failed: ". $sth->errstr; + +map { $custnum{$_->[0]} = 1 } @{ $sth->fetchall_arrayref }; + +$sth = $dbh->prepare($unapplied_credits_sql) or die $dbh->errstr; +$sth->execute or die "unapplied credit search failed: ". $sth->errstr; + +map { $custnum{$_->[0]} = 1 } @{ $sth->fetchall_arrayref }; + +foreach my $custnum ( keys %custnum ) { + + warn "processing customer $custnum\n" if $DEBUG; + + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die "customer $custnum no longer exists!\n"; + + my $error = $cust_main->apply_payments_and_credits; + die $error if $error; + +} + +sub usage { + die "Usage:\n\n freeside-apply_payments_and_credits user\n"; +} + +=head1 NAME + +freeside-apply_payments_and_credits - Command line interface to apply payments and credits to invoice + +=head1 SYNOPSIS + + freeside-apply_payments_and_credits username + +=head1 DESCRIPTION + +Finds unapplied payment and credit amounts and applies them to any outstanding +uncovered invoice amounts. + +B is a username added by freeside-adduser. + +=cut + + + -- cgit v1.2.1 From b717c77e7af226f0f525df39fac49f11b3facd4c Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 26 Jul 2009 18:40:11 +0000 Subject: bring up-to-date wrt 1.7 Conf.pm 1.180.2.49 (2009-7-26), RT#2873 --- FS/FS/Conf_compat17.pm | 154 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 122 insertions(+), 32 deletions(-) diff --git a/FS/FS/Conf_compat17.pm b/FS/FS/Conf_compat17.pm index 0f2e19369..56bc956be 100644 --- a/FS/FS/Conf_compat17.pm +++ b/FS/FS/Conf_compat17.pm @@ -443,10 +443,10 @@ httemplate/docs/config.html }, { - 'key' => 'business-onlinepayment-email_customer', - 'section' => 'billing', - 'description' => 'Controls the "email_customer" flag used by some Business::OnlinePayment processors to enable customer receipts.', - 'type' => 'checkbox', + 'key' => 'business-onlinepayment-email_customer', + 'section' => 'billing', + 'description' => 'Controls the "email_customer" flag used by some Business::OnlinePayment processors to enable customer receipts.', + 'type' => 'checkbox', }, { @@ -642,6 +642,13 @@ httemplate/docs/config.html 'type' => 'text', }, + { + 'key' => 'invoice_subject', + 'section' => 'billing', + 'description' => 'Subject: header on email invoices. Defaults to "Invoice". The following substitutions are available: $name, $name_short, $invoice_number, and $invoice_date.', + 'type' => 'text', + }, + { 'key' => 'invoice_template', 'section' => 'required', @@ -1185,6 +1192,13 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'username-colon', + 'section' => 'username', + 'description' => 'Allow the colon character (:) in usernames.', + 'type' => 'checkbox', + }, + { 'key' => 'safe-part_bill_event', 'section' => 'UI', @@ -1558,8 +1572,8 @@ httemplate/docs/config.html { 'key' => 'paymentforcedtobatch', - 'section' => 'UI', - 'description' => 'Causes per customer payment entry to be forced to a batch processor rather than performed realtime.', + 'section' => 'deprecated', + 'description' => 'See batch-enable_payby and realtime-disable_payby. Used to (for CHEK): Cause per customer payment entry to be forced to a batch processor rather than performed realtime.', 'type' => 'checkbox', }, @@ -1586,6 +1600,14 @@ httemplate/docs/config.html 'select_enum' => [ 'Framed-IP-Address', 'Framed-Address' ], }, + #http://dev.coova.org/svn/coova-chilli/doc/dictionary.chillispot + { + 'key' => 'radius-chillispot-max', + 'section' => '', + 'description' => 'Enable ChilliSpot (and CoovaChilli) Max attributes, specifically ChilliSpot-Max-{Input,Output,Total}-{Octets,Gigawords}.', + 'type' => 'checkbox', + }, + { 'key' => 'svc_acct-alldomains', 'section' => '', @@ -1614,6 +1636,24 @@ httemplate/docs/config.html 'type' => 'textarea', }, + { + 'key' => 'credit_card-recurring_billing_flag', + 'section' => 'billing', + 'description' => 'This controls when the system passes the "recurring_billing" flag on credit card transactions. If supported by your processor (and the Business::OnlinePayment processor module), passing the flag indicates this is a recurring transaction and may turn off the CVV requirement. ', + 'type' => 'select', + 'select_hash' => [ + 'actual_oncard' => 'Default/classic behavior: set the flag if a customer has actual previous charges on the card.', + 'transaction_is_recur' => 'Set the flag if the transaction itself is recurring, irregardless of previous charges on the card.', + ], + }, + + { + 'key' => 'credit_card-recurring_billing_acct_code', + 'section' => 'billing', + 'description' => 'When the "recurring billing" flag is set, also set the "acct_code" to "rebill". Useful for reporting purposes with supported gateways (PlugNPay, others?)', + 'type' => 'checkbox', + }, + { 'key' => 'cvv-save', 'section' => 'billing', @@ -1818,13 +1858,13 @@ httemplate/docs/config.html 'key' => 'address2-search', 'section' => 'UI', 'description' => 'Enable a "Unit" search box which searches the second address field', - 'type' => 'checkbox', + 'type' => 'checkbox', }, { - 'key' => 'cust_main-require_address2', - 'section' => 'UI', - 'description' => 'Second address field is required (on service address only, if billing and service addresses differ). Also enables "Unit" labeling of address2 on customer view and edit pages. Useful for multi-tenant applications. See also: address2-search', + 'key' => 'cust_main-require_address2', + 'section' => 'UI', + 'description' => 'Second address field is required (on service address only, if billing and service addresses differ). Also enables "Unit" labeling of address2 on customer view and edit pages. Useful for multi-tenant applications. See also: address2-search', 'type' => 'checkbox', }, @@ -2025,21 +2065,29 @@ httemplate/docs/config.html 'type' => 'select-sub', 'options_sub' => sub { require FS::Record; require FS::part_pkg; - map { $_->pkgpart => $_->pkg } + map { $_->pkgpart => $_->pkg } FS::Record::qsearch('part_pkg', { disabled=>'' } ); - }, + }, 'option_sub' => sub { require FS::Record; require FS::part_pkg; - my $part_pkg = FS::Record::qsearchs( - 'part_pkg', { 'pkgpart'=>shift } - ); + my $part_pkg = FS::Record::qsearchs( + 'part_pkg', { 'pkgpart'=>shift } + ); $part_pkg ? $part_pkg->pkg : ''; - }, + }, }, { - 'key' => 'batch-enable', + 'key' => 'postal_invoice-recurring_only', 'section' => 'billing', + 'description' => 'The postal invoice fee is omitted on invoices without recurring charges when this is set', + 'type' => 'checkbox', + }, + + { + 'key' => 'batch-enable', + 'section' => 'deprecated', #make sure batch-enable_payby is set for + #everyone before removing 'description' => 'Enable credit card and/or ACH batching - leave disabled for real-time installations.', 'type' => 'checkbox', }, @@ -2227,20 +2275,6 @@ httemplate/docs/config.html 'type' => 'checkbox', }, - { - 'key' => 'cust_main-require_phone', - 'section' => '', - 'description' => 'Require daytime or night for all customer records.', - 'type' => 'checkbox', - }, - - { - 'key' => 'cust_main-require_invoicing_list_email', - 'section' => '', - 'description' => 'Email address field is required: require at least one invoicing email address for all customer records.', - 'type' => 'checkbox', - }, - { 'key' => 'password-generated-allcaps', 'section' => 'password', @@ -2276,6 +2310,20 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'cust_main-require_phone', + 'section' => '', + 'description' => 'Require daytime or night for all customer records.', + 'type' => 'checkbox', + }, + + { + 'key' => 'cust_main-require_invoicing_list_email', + 'section' => '', + 'description' => 'Email address field is required: require at least one invoicing email address for all customer records.', + 'type' => 'checkbox', + }, + { 'key' => 'cancel_credit_type', 'section' => 'billing', @@ -2388,7 +2436,7 @@ httemplate/docs/config.html 'description' => 'Default area code for customers.', 'type' => 'text', }, - + { 'key' => 'cust_bill-max_same_services', 'section' => 'billing', @@ -2396,6 +2444,48 @@ httemplate/docs/config.html 'type' => 'text', }, + { + 'key' => 'suspend_email_admin', + 'section' => '', + 'description' => 'Destination admin email address to enable suspension notices', + 'type' => 'text', + }, + + { + 'key' => 'email_report-subject', + 'section' => '', + 'description' => 'Subject for reports emailed by freeside-fetch. Defaults to "Freeside report".', + 'type' => 'text', + }, + + { + 'key' => 'sg-multicustomer_hack', + 'section' => '', + 'description' => "Don't use this.", + 'type' => 'checkbox', + }, + + { + 'key' => 'queued-max_kids', + 'section' => '', + 'description' => 'Maximum number of queued processes. Defaults to 10.', + 'type' => 'text', + }, + + { + 'key' => 'cancelled_cust-noevents', + 'section' => 'billing', + 'description' => "Don't run events for cancelled customers", + 'type' => 'checkbox', + }, + + { + 'key' => 'svc_broadband-manage_link', + 'section' => 'UI', + 'description' => 'URL for svc_broadband "Manage Device" link. The following substitutions are available: $ip_addr.', + 'type' => 'text', + }, + ); 1; -- cgit v1.2.1 From f83f9129cc2e67d20ef0d512cce9f0b327e26052 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 26 Jul 2009 19:36:08 +0000 Subject: fix the date picker in RT to use jscalendar instead of an HTML popup (that had acquired the page header, eek), RT#1682 --- rt/FREESIDE_MODIFIED | 1 + rt/html/Elements/PageLayout | 1 + rt/html/Elements/SelectDate | 15 +++++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rt/FREESIDE_MODIFIED b/rt/FREESIDE_MODIFIED index dc5e2bc2a..e82078992 100644 --- a/rt/FREESIDE_MODIFIED +++ b/rt/FREESIDE_MODIFIED @@ -12,6 +12,7 @@ lib/RT/URI/freeside/XMLRPC.pm html/Elements/Menu html/Elements/PageLayout html/Elements/QuickCreate + html/Elements/SelectDate html/Elements/SimpleSearch html/Elements/Tabs html/Elements/Footer diff --git a/rt/html/Elements/PageLayout b/rt/html/Elements/PageLayout index 3210b4e3e..b9d15e9d3 100644 --- a/rt/html/Elements/PageLayout +++ b/rt/html/Elements/PageLayout @@ -127,6 +127,7 @@ a:visited:hover.fsdarkbutton { filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff330033',EndColorStr='#ff7e0079') } +<% include('/elements/init_calendar.html') |n %>
-% if ( $show_menu ) { +% if (0) { ##FREESIDE MENUS INSTEAD## if ( $show_menu ) { +%# if ( $show_menu ) { % }
Customers - All customers (even those without an outstanding balance)
- Customers with a balance over days old + All customers (even those without unapplied payments)
+ Customers with unapplied payments days old
diff --git a/rt/html/Elements/SelectDate b/rt/html/Elements/SelectDate index b43f324ac..23df246ce 100644 --- a/rt/html/Elements/SelectDate +++ b/rt/html/Elements/SelectDate @@ -45,10 +45,21 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} +%# in PageLayout instead, once <% include('/elements/init_calendar.html') |n %> + + - <%init> unless ((defined $Default) or ($current <= 0)) { -- cgit v1.2.1 From 6a8c7c021a01b85ce172a230757b000fe2959a31 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 26 Jul 2009 20:23:31 +0000 Subject: fix links --- httemplate/search/svc_broadband.cgi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httemplate/search/svc_broadband.cgi b/httemplate/search/svc_broadband.cgi index 2cb0c1eb3..d0b102957 100755 --- a/httemplate/search/svc_broadband.cgi +++ b/httemplate/search/svc_broadband.cgi @@ -111,13 +111,13 @@ foreach my $router (qsearch('router', {})) { } } -my $link = [ $p.'view/svc_broadband.cgi', 'svcnum' ]; +my $link = [ $p.'view/svc_broadband.cgi?', 'svcnum' ]; #XXX get the router link working my $link_router = sub { my $routernum = $routerbyblock{shift->blocknum}->routernum; [ $p.'view/router.cgi?'.$routernum, 'routernum' ]; }; -my $link_cust = [ $p.'view/cust_main.cgi', 'custnum' ]; +my $link_cust = [ $p.'view/cust_main.cgi?', 'custnum' ]; -- cgit v1.2.1 From f3717767d19f9da888e190f87a04dfa245d658b4 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 27 Jul 2009 03:26:47 +0000 Subject: FCC from 477 improvements #4912 --- FS/FS/Conf.pm | 22 ++++++++++ FS/FS/cust_main.pm | 20 +++++++++ FS/FS/cust_pkg.pm | 7 +++- httemplate/edit/cust_main.cgi | 9 ++++ httemplate/edit/cust_main/bottomfixup.js | 48 +++++++++++++--------- httemplate/edit/cust_main/contact.html | 4 ++ httemplate/elements/location.html | 10 ++++- httemplate/misc/xmlhttp-cust_main-censustract.html | 2 + httemplate/search/cust_pkg.cgi | 6 ++- httemplate/view/cust_main/misc.html | 9 ++++ 10 files changed, 113 insertions(+), 24 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 832322faf..37f55306a 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2604,6 +2604,28 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'census_year', + 'section' => 'UI', + 'description' => 'The year to use in census tract lookups', + 'type' => 'select', + 'select_enum' => [ qw( 2008 2007 2006 ) ], + }, + + { + 'key' => 'company_latitude', + 'section' => 'UI', + 'description' => 'Your company latitude (-90 through 90)', + 'type' => 'text', + }, + + { + 'key' => 'company_longitude', + 'section' => 'UI', + 'description' => 'Your company longitude (-180 thru 180)', + 'type' => 'text', + }, + { 'key' => 'disable_acl_changes', 'section' => '', diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 9d41c4bdf..518ab4d98 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1571,6 +1571,13 @@ sub check { unless ! $self->referral_custnum || qsearchs( 'cust_main', { 'custnum' => $self->referral_custnum } ); + if ( $self->censustract ne '' ) { + $self->censustract =~ /^\s*(\d{9})\.?(\d{2})\s*$/ + or return "Illegal census tract: ". $self->censustract; + + $self->censustract("$1.$2"); + } + if ( $self->ss eq '' ) { $self->ss(''); } else { @@ -7371,6 +7378,19 @@ sub support_services { } +# Return a list of latitude/longitude for one of the services (if any) +sub service_coordinates { + my $self = shift; + + my @svc_X = + grep { $_->latitude && $_->longitude } + map { $_->svc_x } + map { $_->cust_svc } + $self->ncancelled_pkgs; + + scalar(@svc_X) ? ( $svc_X[0]->latitude, $svc_X[0]->longitude ) : () +} + =back =head1 CLASS METHODS diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 4d44692b3..00a030117 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -2377,8 +2377,11 @@ sub search_sql { # parse censustract ### - if ( $params->{'censustract'} =~ /^([.\d]+)$/ and $1 ) { - push @where, "cust_main.censustract = '". $params->{censustract}. "'"; + if ( exists($params->{'censustract'}) ) { + $params->{'censustract'} =~ /^([.\d]*)$/; + my $censustract = "cust_main.censustract = '$1'"; + $censustract .= ' OR cust_main.censustract is NULL' unless $1; + push @where, "( $censustract )"; } ### diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 575131424..8b1d2b59c 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -32,6 +32,15 @@ <% include('cust_main/birthdate.html', $cust_main) %> % } +%# latitude and longitude +% if ( $conf->exists('cust_main-require_censustract') ) { +% my ($latitude, $longitude) = $cust_main->service_coordinates; +% $latitude ||= $conf->config('company_latitude') || ''; +% $longitude ||= $conf->config('company_longitude') || ''; + + +% } + %# contact info % my $same_checked = ''; diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js index 822f98d39..06e8b13b6 100644 --- a/httemplate/edit/cust_main/bottomfixup.js +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -242,7 +242,7 @@ function post_geocode() { var cf = document.CustomerForm; var state_el = cf.elements['ship_state']; var census_data = new Array( - 'year', '2008', // from config value? + 'year', <% $conf->config('census_year') || '2008' %>, 'address', cf.elements['ship_address1'].value, 'city', cf.elements['ship_city'].value, 'state', state_el.options[ state_el.selectedIndex ].value, @@ -296,44 +296,52 @@ function update_censustract(arg) { var tractcode = argsHash['tractcode']; var error = argsHash['error']; + var newcensus = + new String(statecode) + + new String(countycode) + + new String(tractcode).replace(/\s$/, ''); // JSON 1 workaround + set_censustract = function () { - cf.elements['censustract'].value = - document.forms.popupcensustract.elements.censustract.value; + cf.elements['censustract'].value = newcensus cf.submit(); } - if (error) { + if (error || cf.elements['censustract'].value != newcensus) { // popup an entry dialog var choose_censustract = - '

Enter census tract

' + - '
' + + '

Confirm censustract
' + + 'Map service module location

' + ''; choose_censustract = choose_censustract + - '' + - '' + - '' + - ''; - - choose_censustract = choose_censustract + + '' + + '' + + '' + + ''; + + choose_censustract = choose_censustract + '' + + '' + - '
Census Tract:
  
Entered census tractCalculated census tract
' + cf.elements['censustract'].value + + '' + newcensus + '
  
' + - '' + + '' + '' + + '' + + '
' + '
'; + + '
'; - overlib( choose_censustract, CAPTION, 'Choose a census tract', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + overlib( choose_censustract, CAPTION, 'Confirm censustract', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); - setTimeout("document.forms.popupcensustract.elements.censustract.focus()",1); } else { - cf.elements['censustract'].value = - new String(statecode) + - new String(countycode) + - new String(tractcode); cf.submit(); } diff --git a/httemplate/edit/cust_main/contact.html b/httemplate/edit/cust_main/contact.html index 2691da652..3bed54b85 100644 --- a/httemplate/edit/cust_main/contact.html +++ b/httemplate/edit/cust_main/contact.html @@ -111,6 +111,10 @@ $cust_main->set($pre.'state', $statedefault ) $cust_main->set('stateid_state', $cust_main->state ) unless $pre || $cust_main->get('stateid_state'); +if ( $conf->exists('cust_main-require_censustract') ) { + $opt{censustract} ||= $cust_main->censustract; +} + #my($county_html, $state_html, $country_html) = # FS::cust_main_county::regionselector( $cust_main->get($pre.'county'), # $cust_main->get($pre.'state'), diff --git a/httemplate/elements/location.html b/httemplate/elements/location.html index 1bdbf9604..07aaa69f0 100644 --- a/httemplate/elements/location.html +++ b/httemplate/elements/location.html @@ -87,7 +87,15 @@ Example: % if ( !$pre ) { % } else { - +% if ( $pre eq 'ship_' && $conf->exists('cust_main-require_censustract') ) { + Census tract
(automatic) + + + + +% } else { + +% } % } <%init> diff --git a/httemplate/misc/xmlhttp-cust_main-censustract.html b/httemplate/misc/xmlhttp-cust_main-censustract.html index 05636d3fb..9d588d712 100644 --- a/httemplate/misc/xmlhttp-cust_main-censustract.html +++ b/httemplate/misc/xmlhttp-cust_main-censustract.html @@ -86,6 +86,8 @@ if ( $sub eq 'censustract' ) { } $error = "No census tract found" unless $return->{tractcode}; + $return->{tractcode} .= ' ' + unless $error || $JSON::VERSION >= 2; #broken JSON 1 workaround } #unless ($res->code eq '200') diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index a2ea3c582..f6a3620d3 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -162,10 +162,14 @@ my $money_char = $conf->config('money_char') || '$'; $search_hash{'query'} = $cgi->keywords; - for ( qw(agentnum magic status classnum pkgpart custom censustract) ) { + for ( qw(agentnum magic status classnum pkgpart custom ) ) { $search_hash{$_} = $cgi->param($_) if $cgi->param($_); } + for my $param ( qw(censustract) ) { + $search_hash{$param} = $cgi->param($param) || '' + if ( grep { /$param/ } $cgi->param ); + } my @report_option = $cgi->param('report_option') if $cgi->param('report_option'); diff --git a/httemplate/view/cust_main/misc.html b/httemplate/view/cust_main/misc.html index 91b304b5d..71e8d6973 100644 --- a/httemplate/view/cust_main/misc.html +++ b/httemplate/view/cust_main/misc.html @@ -98,6 +98,15 @@ % } +% if ( $conf->exists('cust_main-require_censustract') ) { + + + Census tract + <% $cust_main->censustract %> + + +% } + <%init> -- cgit v1.2.1 From 44a63e5978af2b5b4e00cabbc4b3541df4144305 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 27 Jul 2009 06:17:20 +0000 Subject: add deprecated config options back to Conf.pm to fix "unapplypayments" fails existential comparison errors, RT#2927 --- FS/FS/Conf.pm | 98 +++++++++++++++++++++++++++++++++++++++ httemplate/config/config-view.cgi | 2 + 2 files changed, 100 insertions(+) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 37f55306a..0fe3ca977 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -714,6 +714,20 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'unapplypayments', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, now controlled by ACLs. Used to enable "unapplication" of unclosed payments.', + 'type' => 'checkbox', + }, + + { + 'key' => 'unapplycredits', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, now controlled by ACLs. Used to nable "unapplication" of unclosed credits.', + 'type' => 'checkbox', + }, + { 'key' => 'dirhash', 'section' => 'shell', @@ -935,6 +949,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'invoice_send_receipts', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, this used to send an invoice copy on payments and credits. See the payment_receipt_email and XXXX instead.', + 'type' => 'checkbox', + }, + { 'key' => 'payment_receipt_email', 'section' => 'billing', @@ -1023,6 +1044,13 @@ worry that config_items is freeside-specific and icky. # 'description' => 'Directory which contains domain registry information. Each registry is a directory.', # }, + { + 'key' => 'report_template', + 'section' => 'deprecated', + 'description' => 'Deprecated template file for reports.', + 'type' => 'textarea', + }, + { 'key' => 'maxsearchrecordsperpage', 'section' => 'UI', @@ -1693,6 +1721,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'text', }, + { + 'key' => 'users-allow_comp', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, enable the Complimentary customer access right instead. Was: Usernames (Freeside users, created with freeside-adduser) which can create complimentary customers, one per line. If no usernames are entered, all users can create complimentary accounts.', + 'type' => 'textarea', + }, + { 'key' => 'credit_card-recurring_billing_flag', 'section' => 'billing', @@ -1928,6 +1963,27 @@ worry that config_items is freeside-specific and icky. 'per_agent' => 1, }, + { + 'key' => 'echeck-void', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, now controlled by ACLs. Used to enable local-only voiding of echeck payments in addition to refunds against the payment gateway', + 'type' => 'checkbox', + }, + + { + 'key' => 'cc-void', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, now controlled by ACLs. Used to enable local-only voiding of credit card payments in addition to refunds against the payment gateway', + 'type' => 'checkbox', + }, + + { + 'key' => 'unvoid', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, now controlled by ACLs. Used to enable unvoiding of voided payments', + 'type' => 'checkbox', + }, + { 'key' => 'address2-search', 'section' => 'UI', @@ -2939,6 +2995,48 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { key => "apacheroot", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "apachemachine", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "apachemachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "bindprimary", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "bindsecondaries", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "bsdshellmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "cyrus", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "cp_app", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "erpcdmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "icradiusmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "icradius_mysqldest", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "icradius_mysqlsource", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "icradius_secrets", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "maildisablecatchall", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "mxmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "nsmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "arecords", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "cnamerecords", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "nismachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "qmailmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "radiusmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "sendmailconfigpath", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "sendmailmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "sendmailrestart", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "shellmachine", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "shellmachine-useradd", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "shellmachine-userdel", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "shellmachine-usermod", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "shellmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "radiusprepend", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "textradiusprepend", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "username_policy", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "vpopmailmachines", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "vpopmailrestart", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "safe-part_pkg", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "selfservice_server-quiet", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "signup_server-quiet", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "signup_server-email", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "vonage-username", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "vonage-password", section => "deprecated", description => "DEPRECATED", type => "text" }, + { key => "vonage-fromnumber", section => "deprecated", description => "DEPRECATED", type => "text" }, + ); 1; diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index c5ac1a685..9e9e64eb2 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -78,6 +78,8 @@ Click on a configuration value to change it. % foreach my $agent ( @agents ) { % my $agentnum = $agent ? $agent->agentnum : ''; % +% next if $section eq 'deprecated' && ! $conf->exists($i->key, $agentnum); +% % my $label = $i->key; % $label = '['. $agent->agent. "] $label" % if $agent && $cgi->param('showagent'); -- cgit v1.2.1 From b00657d2dd62614568501df47d1be4cbfa15eb48 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 27 Jul 2009 09:07:24 +0000 Subject: voided payment report, RT#5786 --- httemplate/elements/menu.html | 32 ++++++++++++++++------ httemplate/search/cust_pay_void.html | 13 +++++++++ httemplate/search/elements/cust_pay_or_refund.html | 4 ++- httemplate/search/report_cust_pay.html | 8 ++++-- httemplate/view/cust_pay.html | 32 +++++++++++++++++----- httemplate/view/cust_pay_void.html | 1 + 6 files changed, 72 insertions(+), 18 deletions(-) create mode 100755 httemplate/search/cust_pay_void.html create mode 100644 httemplate/view/cust_pay_void.html diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 999fa43ea..6b256c8d8 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -135,10 +135,19 @@ foreach my $svcdb ( FS::part_svc->svc_tables() ) { } if ( $svcdb eq 'svc_acct' ) { + $report_svc{"All $lcname never logged in"} = [ svc_url( %svc_url, 'query' => "magic=nologin;sortby=svcnum" ), '', ]; + + } elsif ( $svcdb eq 'svc_phone' ) { + + $report_svc{"${name}' total usage by time period"} = + [ $fsurl. 'search/report_svc_phone.html', + 'Total usage (minutes, and amount billed) for the specified time period, per phone number.', + ]; + } if ( $curuser->access_right('View/link unlinked services') ) { @@ -204,9 +213,20 @@ tie my %report_ticketing, 'Tie::IxHash', tie my %report_bill_event, 'Tie::IxHash', 'All billing events' => [ $fsurl.'search/report_cust_event.html', 'All billing events for a date range' ], 'Billing event errors' => [ $fsurl.'search/report_cust_event.html?failed=1', 'Failed credit cards, processor or printer problems, etc.' ], - 'All invoice events' => [ $fsurl.'search/cust_bill_event.html', 'Reports on deprecated, old-style invoice events for a date range' ], - 'Invoice event errors' => [ $fsurl.'search/cust_bill_event.html?failed=1', 'Reports on deprecated, old-style events for failed credit cards, processor or printer problems, etc.' ], +# 'All invoice events' => [ $fsurl.'search/cust_bill_event.html', 'Reports on deprecated, old-style invoice events for a date range' ], +# 'Invoice event errors' => [ $fsurl.'search/cust_bill_event.html?failed=1', 'Reports on deprecated, old-style events for failed credit cards, processor or printer problems, etc.' ], +; + +tie my %report_payments, 'Tie::IxHash', + 'Payments' => [ $fsurl.'search/report_cust_pay.html', 'Payment report (by type and/or date range)' ], ; +$report_payments{'Pending Payments'} = [ $fsurl.'search/cust_pay_pending.html?magic=_date;statusNOT=done', 'Pending real-time payments' ] + if $curuser->access_right('View customer pending payments'); +$report_payments{'Voided Payments'} = [ $fsurl.'search/report_cust_pay.html?void=1', 'Voided payment report (by type and/or date range)' ] + if $curuser->access_right('View customer pending payments'); +$report_payments{'Payment Batches'} = [ $fsurl.'search/pay_batch.html', 'Payment batches (by status and/or date range)' ] + if $conf->exists('batch-enable') || $conf->config('batch-enable_payby'); +$report_payments{'Unapplied Payment Aging'} = [ $fsurl.'search/report_unapplied_cust_pay.html', 'Unapplied payment aging report' ]; tie my %report_financial, 'Tie::IxHash'; if($curuser->access_right('Financial reports')) { @@ -215,13 +235,7 @@ if($curuser->access_right('Financial reports')) { 'Sales, Credits and Receipts' => [ $fsurl.'graph/report_money_time.html', 'Sales, credits and receipts summary graph' ], 'Sales Report' => [ $fsurl.'graph/report_cust_bill_pkg.html', 'Sales report and graph (by agent, package class and/or date range)' ], 'Credit Report' => [ $fsurl.'search/report_cust_credit.html', 'Credit report (by employee and/or date range)' ], - 'Payment Report' => [ $fsurl.'search/report_cust_pay.html', 'Payment report (by type and/or date range)' ], ); - $report_financial{'Pending Payment Report'} = [ $fsurl.'search/cust_pay_pending.html?magic=_date;statusNOT=done', 'Pending real-time payments' ] - if $curuser->access_right('View customer pending payments'); - $report_financial{'Payment Batch Report'} = [ $fsurl.'search/pay_batch.html', 'Payment batches (by status and/or date range)' ] - if $conf->exists('batch-enable') || $conf->config('batch-enable_payby'); - $report_financial{'Unapplied payment Aging'} = [ $fsurl.'search/report_unapplied_cust_pay.html', 'Unapplied payment aging report' ]; $report_financial{'A/R Aging'} = [ $fsurl.'search/report_receivables.html', 'Accounts Receivable Aging report' ]; $report_financial{'Prepaid Income'} = [ $fsurl.'search/report_prepaid_income.html', 'Prepaid income (unearned revenue) report' ]; $report_financial{'Sales Tax Liability'} = [ $fsurl.'search/report_tax.html', 'Sales tax liability report (internal taxclass system)' ]; @@ -239,6 +253,8 @@ $report_menu{'Customers'} = [ \%report_customers, 'Customer reports' ] if $curuser->access_right('List customers'); $report_menu{'Invoices'} = [ \%report_invoices, 'Invoice reports' ] if $curuser->access_right('List invoices'); +$report_menu{'Payments'} = [ \%report_payments, 'Payment reports' ] + if $curuser->access_right('Financial reports'); $report_menu{'Packages'} = [ \%report_packages, 'Package reports' ] if $curuser->access_right('List packages'); $report_menu{'Services'} = [ \%report_services, 'Services reports' ] diff --git a/httemplate/search/cust_pay_void.html b/httemplate/search/cust_pay_void.html new file mode 100755 index 000000000..431bb2c6b --- /dev/null +++ b/httemplate/search/cust_pay_void.html @@ -0,0 +1,13 @@ +<% include( 'elements/cust_pay_or_refund.html', + 'thing' => 'pay_void', + 'amount_field' => 'paid', + 'name_singular' => 'voided payment', + 'name_verb' => 'voided', # 'paid', + 'disable_by' => 1, #showing original not voiding otaker + 'addl_header' => [ 'Void Date', ], # 'Void Reason' ], + 'addl_fields' => [ + sub { time2str('%b %d %Y', shift->void_date ) }, + #'reason', + ], + ) +%> diff --git a/httemplate/search/elements/cust_pay_or_refund.html b/httemplate/search/elements/cust_pay_or_refund.html index add8427ca..acd57912f 100755 --- a/httemplate/search/elements/cust_pay_or_refund.html +++ b/httemplate/search/elements/cust_pay_or_refund.html @@ -288,7 +288,9 @@ if ( ( $curuser->access_right('View invoices') #XXX for now && ! $opt{'disable_link'} ) { - $link = [ "${p}view/cust_$thing.html?${thing}num=", $thing.'num' ] + my $key = $thing eq 'pay_void' ? 'paynum' : $thing.'num'; + my $q = ( $thing eq 'pay_void' ? 'void=1;' : '' ). "$key="; + $link = [ "${p}view/cust_$thing.html?$q", $key ] } my $cust_link = sub { diff --git a/httemplate/search/report_cust_pay.html b/httemplate/search/report_cust_pay.html index 06271313f..a9695acb7 100644 --- a/httemplate/search/report_cust_pay.html +++ b/httemplate/search/report_cust_pay.html @@ -1,6 +1,6 @@ -<% include('/elements/header.html', 'Payment report' ) %> +<% include('/elements/header.html', $title ) %> -
+ @@ -76,4 +76,8 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); +my $void = $cgi->param('void') ? 1 : 0; + +my $title = $void ? 'Voided payment report' : 'Payment report'; + diff --git a/httemplate/view/cust_pay.html b/httemplate/view/cust_pay.html index c36d76904..a5c99ac55 100644 --- a/httemplate/view/cust_pay.html +++ b/httemplate/view/cust_pay.html @@ -1,12 +1,12 @@ % if ( $link eq 'popup' ) { - <% include('/elements/header-popup.html', "Payment Receipt" ) %> + <% include('/elements/header-popup.html', "$thing Receipt" ) %>
Print

% } elsif ( $link eq 'print' ) { - <% include('/elements/header-popup.html', "Payment Receipt" ) %> + <% include('/elements/header-popup.html', "$thing Receipt" ) %> % #it would be nice if the menubar could be hidden for print, but better to % # have it available than not, otherwise the user winds up at a dead end @@ -18,7 +18,7 @@ % } else { - <% include('/elements/header.html', "Payment Receipt", menubar( + <% include('/elements/header.html', "$thing Receipt", menubar( "View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum", 'Print receipt' => $pr_link, )) @@ -48,6 +48,20 @@ +% if ( $void ) { + + + + + + +%# +%# +%# +%# + +% } + @@ -112,16 +126,20 @@ if ( $cgi->param('link') =~ /^(\w+)$/ ) { $link = $1; } +my $void = $cgi->param('void') ? 1 : 0; +my $thing = $void ? 'Voided Payment' : 'Payment'; +my $table = $void ? 'cust_pay_void' : 'cust_pay'; + my $cust_pay = qsearchs({ - 'select' => 'cust_pay.*', - 'table' => 'cust_pay', + 'select' => "$table.*", + 'table' => $table, 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', 'hashref' => { 'paynum' => $paynum }, 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, }); -die "Payment #$paynum not found!" unless $cust_pay; +die "$thing #$paynum not found!" unless $cust_pay; -my $pr_link = "${p}view/cust_pay.html?link=print;paynum=$paynum"; +my $pr_link = "${p}view/cust_pay.html?link=print;paynum=$paynum;void=$void"; my $custnum = $cust_pay->custnum; my $display_custnum = $cust_pay->cust_main->display_custnum; diff --git a/httemplate/view/cust_pay_void.html b/httemplate/view/cust_pay_void.html new file mode 100644 index 000000000..8c22170d6 --- /dev/null +++ b/httemplate/view/cust_pay_void.html @@ -0,0 +1 @@ +<% include('cust_pay.html', @_, 'void' => 1 ) %> -- cgit v1.2.1 From 342de0c0922c4fac8d6ace5a38670ace35366571 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 27 Jul 2009 09:59:06 +0000 Subject: searching for voided payments by void date as well, RT#5786 --- httemplate/search/elements/cust_pay_or_refund.html | 8 ++++- httemplate/search/report_cust_pay.html | 35 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/httemplate/search/elements/cust_pay_or_refund.html b/httemplate/search/elements/cust_pay_or_refund.html index acd57912f..874bd8aa3 100755 --- a/httemplate/search/elements/cust_pay_or_refund.html +++ b/httemplate/search/elements/cust_pay_or_refund.html @@ -117,7 +117,6 @@ if ( $cgi->param('magic') ) { my $orderby; if ( $cgi->param('magic') eq '_date' ) { - if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) { push @search, "agentnum = $1"; # $search{'agentnum'} = $1; my $agent = qsearchs('agent', { 'agentnum' => $1 } ); @@ -219,6 +218,13 @@ if ( $cgi->param('magic') ) { push @search, "_date >= $beginning ", "_date <= $ending"; + if ( $thing eq 'pay_void' ) { + my($v_beginning, $v_ending) = + FS::UI::Web::parse_beginning_ending($cgi, 'void'); + push @search, "void_date >= $v_beginning ", + "void_date <= $v_ending"; + } + push @search, FS::UI::Web::parse_lt_gt($cgi, $amount_field ); $orderby = '_date'; diff --git a/httemplate/search/report_cust_pay.html b/httemplate/search/report_cust_pay.html index a9695acb7..dd2358ad1 100644 --- a/httemplate/search/report_cust_pay.html +++ b/httemplate/search/report_cust_pay.html @@ -3,7 +3,13 @@ -
<% time2str"%a %b %o, %Y %r", $cust_pay->_date %>
Void Date<% time2str"%a %b %o, %Y %r", $cust_pay->void_date %>
Void reason<% $cust_pay->reason %>
Amount <% $money_char. $cust_pay->paid %>
+
+ + + + @@ -55,7 +61,32 @@ ) %> - <% include( '/elements/tr-input-beginning_ending.html' ) %> + + + + + +% if ( $void ) { + + + + +% } <% include( '/elements/tr-input-lessthan_greaterthan.html', 'label' => 'Amount', -- cgit v1.2.1 From 8d02e9450e5999da1015ac4c74f7a478716554f1 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 27 Jul 2009 19:51:16 +0000 Subject: fix spacing --- httemplate/misc/cancel_pkg.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/misc/cancel_pkg.html b/httemplate/misc/cancel_pkg.html index 1228eb1af..607ce13c4 100755 --- a/httemplate/misc/cancel_pkg.html +++ b/httemplate/misc/cancel_pkg.html @@ -17,7 +17,7 @@

-<% ucfirst($method) . $part_pkg->pkg_comment %> +<% ucfirst($method) %> <% $part_pkg->pkg_comment %> <% ntable("#cccccc", 2) %> % if ($method eq 'expire' || $method eq 'adjourn') { -- cgit v1.2.1 From cd2241d7ea1ce53a626adfd58a908cfd822c618c Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 28 Jul 2009 02:12:50 +0000 Subject: Add no_queue option to shellcommands exports --- FS/FS/part_export/shellcommands.pm | 24 +++++++++++++++++++----- FS/FS/part_export/shellcommands_withdomain.pm | 3 +++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm index c55fa367e..e375302a4 100644 --- a/FS/FS/part_export/shellcommands.pm +++ b/FS/FS/part_export/shellcommands.pm @@ -65,6 +65,9 @@ tie my %options, 'Tie::IxHash', 'Radius group mapping to reason (via template user)', type => 'textarea', }, + 'no_queue' => { label => 'Run command immediately', + type => 'checkbox', + }, ; %info = ( @@ -367,12 +370,23 @@ sub _export_replace { my $command_string = eval(qq("$command")); - $self->shellcommands_queue( $new->svcnum, - user => $self->option('user')||'root', - host => $self->machine, - command => $command_string, - stdin_string => $stdin_string, + my @ssh_cmd_args = ( + user => $self->option('user') || 'root', + host => $self->machine, + command => $command_string, + stdin_string => $stdin_string, ); + + if($self->options('no_queue')) { + # discard return value just like freeside-queued. + eval { ssh_cmd(@ssh_cmd_args) }; + $error = $@; + return $error. ' ('. $self->exporttype. ' to '. $self->machine. ')' + if $error; + } + else { + $self->shellcommands_queue( $new->svcnum, @ssh_cmd_args ); + } } #a good idea to queue anything that could fail or take any time diff --git a/FS/FS/part_export/shellcommands_withdomain.pm b/FS/FS/part_export/shellcommands_withdomain.pm index 7c5d9045f..e1f47e410 100644 --- a/FS/FS/part_export/shellcommands_withdomain.pm +++ b/FS/FS/part_export/shellcommands_withdomain.pm @@ -51,6 +51,9 @@ tie my %options, 'Tie::IxHash', type=>'select', options=>[qw(crypt md5)], default => 'crypt', }, + 'no_queue' => { label => 'Run command immediately', + type => 'checkbox', + }, ; %info = ( -- cgit v1.2.1 From e1b1693a656964c6db0b8a3fb85494014434dcb1 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 28 Jul 2009 21:17:45 +0000 Subject: adding a basic change history using history tables, RT#1005, RT#4357 --- FS/FS/AccessRight.pm | 1 + FS/FS/Conf.pm | 9 +- FS/FS/Mason.pm | 12 +- FS/FS/svc_external.pm | 1 + httemplate/pref/pref.html | 28 ++- httemplate/view/cust_main.cgi | 12 +- httemplate/view/cust_main/change_history.html | 302 ++++++++++++++++++++++++++ 7 files changed, 345 insertions(+), 20 deletions(-) create mode 100644 httemplate/view/cust_main/change_history.html diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index 3157d5ff0..29cecd5f2 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -94,6 +94,7 @@ tie my %rights, 'Tie::IxHash', 'View customer', #'View Customer | View tickets', 'Edit customer', + 'View customer history', 'Cancel customer', 'Complimentary customer', #aka users-allow_comp { rightname=>'Delete customer', desc=>"Enable customer deletions. Be very careful! Deleting a customer will remove all traces that this customer ever existed! It should probably only be used when auditing a legacy database. Normally, you cancel all of a customer's packages if they cancel service." }, #aka. deletecustomers diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 0fe3ca977..20abd4546 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2318,6 +2318,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'text', }, + { + 'key' => 'change_history-years', + 'section' => 'UI', + 'description' => 'Number of years of change history to show by default. Currently defaults to 0.5.', + 'type' => 'text', + }, + { 'key' => 'cust_main-packages-years', 'section' => 'UI', @@ -2976,7 +2983,7 @@ worry that config_items is freeside-specific and icky. 'tickets' => 'Tickets', 'packages' => 'Packages', 'payment_history' => 'Payment History', - #'' => 'Change History', + 'change_history' => 'Change History', 'jumbo' => 'Jumbo', ], }, diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index ac11026cf..ed99bf694 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -186,6 +186,16 @@ Initializes the Mason environment, loads all Freeside and RT libraries, etc. use FS::part_pkg_taxrate; use FS::tax_rate; use FS::part_pkg_report_option; + use FS::h_cust_pkg; + use FS::h_svc_acct; + use FS::h_svc_broadband; + use FS::h_svc_domain; + #use FS::h_domain_record; + use FS::h_svc_external; + use FS::h_svc_forward; + use FS::h_svc_phone; + #use FS::h_phone_device; + use FS::h_svc_www; # Sammath Naur if ( %%%RT_ENABLED%%% ) { @@ -223,7 +233,7 @@ Initializes the Mason environment, loads all Freeside and RT libraries, etc. #slow, unreliable, segfaults and is optional #see rt/html/Ticket/Elements/ShowTransactionAttachments - #use Text::Quoted; + use Text::Quoted; #?#use File::Path qw( rmtree ); #?#use File::Glob qw( bsd_glob ); diff --git a/FS/FS/svc_external.pm b/FS/FS/svc_external.pm index 0fb391fef..aca7c1bcc 100644 --- a/FS/FS/svc_external.pm +++ b/FS/FS/svc_external.pm @@ -95,6 +95,7 @@ sub label { substr('0000000000'.uc($self->title), -10); } else { #$self->SUPER::label; + return $self->id unless $self->title =~ /\S/; $self->id. ' - '. $self->title; } } diff --git a/httemplate/pref/pref.html b/httemplate/pref/pref.html index 8bdf6c09c..562ef2980 100644 --- a/httemplate/pref/pref.html +++ b/httemplate/pref/pref.html @@ -124,25 +124,23 @@ Vonage integration (see Click2Call <% include('/elements/footer.html') %> -<%once> - - #false laziness w/view/cust_main.cgi and Conf.pm (cust_main-default_view) - - tie my %customer_views, 'Tie::IxHash', - 'Basics' => 'basics', - 'Notes' => 'notes', #notes and files? - 'Tickets' => 'tickets', - 'Packages' => 'packages', - 'Payment History' => 'payment_history', - #'Change History' => '', - 'Jumbo' => 'jumbo', - ; - - <%init> my $curuser = $FS::CurrentUser::CurrentUser; +#false laziness w/view/cust_main.cgi and Conf.pm (cust_main-default_view) + +tie my %customer_views, 'Tie::IxHash', + 'Basics' => 'basics', + 'Notes' => 'notes', #notes and files? + 'Tickets' => 'tickets', + 'Packages' => 'packages', + 'Payment History' => 'payment_history', +; +$customer_views{'Change History'} = 'change_history' + if $curuser->access_right('View customer history'); +$customer_views{'Jumbo'} = 'jumbo'; + # XSS via your own preferences? seems unlikely, but nice try anyway... ( $curuser->option('menu_position') || 'top' ) =~ /^(\w+)$/ or die "illegal menu_position"; diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 88fd03713..78bcb1fc1 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -113,6 +113,7 @@ Comments % if ( ! $conf->exists('cust_main-disable_notes') || $notecount) { % unless ( $view eq 'notes' && $cust_main->comments !~ /[^\s\n\r]/ ) { +
Notes
% } @@ -180,6 +181,10 @@ Comments % } +% if ( $view eq 'change_history' ) { # || $view eq 'jumbo' + <% include('cust_main/change_history.html', $cust_main ) %> +% } + <% include('/elements/footer.html') %> <%init> @@ -213,11 +218,12 @@ tie my %views, 'Tie::IxHash', 'Notes' => 'notes', #notes and files? ; $views{'Tickets'} = 'tickets' - if $conf->config('ticket_system'); + if $conf->config('ticket_system'); $views{'Packages'} = 'packages'; $views{'Payment History'} = 'payment_history' - unless $conf->config('payby-default' eq 'HIDE'); -#$views{'Change History'} = ''; + unless $conf->config('payby-default' eq 'HIDE'); +$views{'Change History'} = 'change_history' + if $curuser->access_right('View customer history'); $views{'Jumbo'} = 'jumbo'; my %viewname = reverse %views; diff --git a/httemplate/view/cust_main/change_history.html b/httemplate/view/cust_main/change_history.html new file mode 100644 index 000000000..1700bc34b --- /dev/null +++ b/httemplate/view/cust_main/change_history.html @@ -0,0 +1,302 @@ +% if ( int( time - (keys %years)[0] * 31556736 ) > $start ) { + Show: +% my $chy = $cgi->param('change_history-years'); +% foreach my $y (keys %years) { +% if ( $y == $years ) { + <% $years{$y} %> +% } else { +% $cgi->param('change_history-years', $y); + <% $years{$y} %> +% } +% last if int( time - $y * 31556736 ) < $start; +% } +% $cgi->param('change_history-years', $chy); +% } + +<% include("/elements/table-grid.html") %> +% my $bgcolor1 = '#eeeeee'; +% my $bgcolor2 = '#ffffff'; +% my $bgcolor = ''; + +
+ + + + + + + + +% foreach my $item ( sort { $a->history_date <=> $b->history_date +% #|| table order +% || $a->historynum <=> $b->historynum +% } +% @history +% ) +% { +% +% my $history_other = ''; +% my $act = $item->history_action; +% if ( $act =~ /^replace/ ) { +% my $pkey = $item->primary_key; +% my $date = $item->history_date; +% $history_other = qsearchs({ +% 'table' => $item->table, +% 'hashref' => { $pkey => $item->$pkey(), +% 'history_action' => $replace_other{$act}, +% 'historynum' => { 'op' => $replace_dir{$act}, +% 'value' => $item->historynum +% }, +% }, +% 'extra_sql' => " +% AND history_date $replace_direq{$act} $date +% AND ($date $replace_op{$act} $fuzz) $replace_direq{$act} history_date +% ORDER BY historynum $replace_ord{$act} LIMIT 1 +% ", +% }); +% } +% +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; +% } + + + + + + + + + + +% } + +
+ Search options +
Payments of type:
Payment + + <% include( '/elements/tr-input-beginning_ending.html', + layout => 'horiz', + ) + %> +
+
Voided + + <% include( '/elements/tr-input-beginning_ending.html', + prefix => 'void', + layout => 'horiz', + ) + %> +
+
UserDateTimeItemActionDescription
+% my $otaker = $item->history_user; +% $otaker = 'auto billing' if $otaker eq 'fs_daily'; +% $otaker = 'customer self-service' if $otaker eq 'fs_selfservice'; +% $otaker = 'job queue' if $otaker eq 'fs_queue'; + <% $otaker %> + +% my $d = time2str('%b %o, %Y', $item->history_date ); +% $d =~ s/ / /g; + <% $d %> + +% my $t = time2str('%r', $item->history_date ); +% $t =~ s/ / /g; + <% $t %> + +% my $label = $h_tables{$item->table}; +% $label = &{ $h_table_labelsub{$item->table} }( $item, $label ) +% if $h_table_labelsub{$item->table}; + <% $label %> + + <% $action{$item->history_action} %> + + <% join(', ', + map { my $value = ( $_ =~ /(^pay(info|cvv)|^ss|_password)$/ ) + ? 'N/A' + : $item->get($_); + $value = substr($value, 0, 77).'...' if length($value) > 80; + $value = encode_entities($value); + "$_:$value"; + } + grep { $history_other + ? ( $item->get($_) ne $history_other->get($_) ) + : ( $item->get($_) =~ /\S/ ) + } + grep { ! /^(history|custnum$)/i } + $item->fields + ) + %> +
+<%once> + +# length-switching + +tie my %years, 'Tie::IxHash', + .5 => '6 months', + 1 => '1 year', + 2 => '2 years', + 5 => '5 years', + 39 => 'all history', +; + +# labeling history rows + +my %action = ( + 'insert' => 'Insert', #'Create', + 'replace_old' => 'Change from', + 'replace_new' => 'Change to', + 'delete' => 'Remove', +); + +# finding the other replace row + +my %replace_other = ( + 'replace_new' => 'replace_old', + 'replace_old' => 'replace_new', +); +my %replace_dir = ( + 'replace_new' => '<', + 'replace_old' => '>', +); +my %replace_direq = ( + 'replace_new' => '<=', + 'replace_old' => '>=', +); +my %replace_op = ( + 'replace_new' => '-', + 'replace_old' => '+', +); +my %replace_ord = ( + 'replace_new' => 'DESC', + 'replace_old' => 'ASC', +); + +my $fuzz = 5; #seems like a lot + +# which tables to search and what to call them + +tie my %tables, 'Tie::IxHash', + 'cust_main' => 'Customer', + 'cust_main_invoice' => 'Invoice destination', + 'cust_pkg' => 'Package', + #? or just svc_* ? 'cust_svc' => + 'svc_acct' => 'Account', + 'radius_usergroup' => 'RADIUS group', + 'svc_domain' => 'Domain', + 'svc_www' => 'Hosting', + 'svc_forward' => 'Mail forward', + 'svc_broadband' => 'Broadband', + 'svc_external' => 'External service', + 'svc_phone' => 'Phone', + 'phone_device' => 'Phone device', + #? it gets provisioned anyway 'phone_avail' => 'Phone', +; + +my $svc_join = 'JOIN cust_svc USING ( svcnum ) JOIN cust_pkg USING ( pkgnum )'; + +my %table_join = ( + 'svc_acct' => $svc_join, + 'radius_usergroup' => $svc_join, + 'svc_domain' => $svc_join, + 'svc_www' => $svc_join, + 'svc_forward' => $svc_join, + 'svc_broadband' => $svc_join, + 'svc_external' => $svc_join, + 'svc_phone' => $svc_join, + 'phone_device' => $svc_join, +); + +my %h_tables = map { ( "h_$_" => $tables{$_} ) } keys %tables; + +my %pkgpart = (); +my $pkg_labelsub = sub { + my($item, $label) = @_; + $pkgpart{$item->pkgpart} ||= $item->part_pkg->pkg; + $label. ': '. encode_entities($pkgpart{$item->pkgpart}). ''; +}; + +my $svc_labelsub = sub { + my($item, $label) = @_; + $label. ': '. encode_entities($item->label). ''; +}; + +my %h_table_labelsub = ( + 'h_cust_pkg' => $pkg_labelsub, + 'h_svc_acct' => $svc_labelsub, + #'h_radius_usergroup' => + 'h_svc_domain' => $svc_labelsub, + 'h_svc_www' => $svc_labelsub, + 'h_svc_forward' => $svc_labelsub, + 'h_svc_broadband' => $svc_labelsub, + 'h_svc_external' => $svc_labelsub, + 'h_svc_phone' => $svc_labelsub, + #'h_phone_device' +); + +# cust_main +# cust_main_invoice + +# cust_pkg +# cust_pkg_option? +# cust_pkg_detail +# cust_pkg_reason? no + +#cust_svc +#cust_svc_option? +#svc_* +# svc_acct +# radius_usergroup +# acct_snarf? is this even used? +# svc_domain +# domain_record +# registrar +# svc_forward +# svc_www +# svc_broadband +# (virtual fields? eh... maybe when they're real) +# svc_external +# svc_phone +# phone_device +# phone_avail + +# future: + +# inventory_item (from services) +# pkg_referral? (changed?) + +#random others: + +# cust_location? +# cust_main-exemption?? (295.ca named tax exemptions) + + +<%init> + +my( $cust_main ) = @_; + +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access deined" + unless $curuser->access_right('View customer history'); + +# find out the beginning of this customer history, if possible +my $h_insert = qsearchs({ + 'table' => 'h_cust_main', + 'hashref' => { 'custnum' => $cust_main->custnum, + 'history_action' => 'insert', + }, + 'extra_sql' => 'ORDER BY historynum LIMIT 1', +}); +my $start = $h_insert ? $h_insert->history_date : 0; + +# retreive the history + +my @history = (); + +my $years = $conf->config('change_history-years') || .5; +if ( $cgi->param('change_history-years') =~ /^([\d\.]+)$/ ) { + $years = $1; +} +my $newer_than = int( time - $years * 31556736 ); #60*60*24*365.24 + +local($FS::Record::nowarn_classload) = 1; + +foreach my $table ( keys %tables ) { + my @items = qsearch({ + 'table' => "h_$table", + 'addl_from' => $table_join{$table}, + 'hashref' => { 'history_date' => { op=>'>=', value=>$newer_than }, }, + 'extra_sql' => ' AND custnum = '. $cust_main->custnum, + }); + push @history, @items; + +} + + -- cgit v1.2.1 From 50f5d60aef5ee82be33c978db6424372bfd7995b Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 28 Jul 2009 22:21:40 +0000 Subject: feature to email CSV of CDRs with invoices #5727 --- FS/FS/Conf.pm | 7 +++++++ FS/FS/Schema.pm | 1 + FS/FS/cust_bill.pm | 32 ++++++++++++++++++++++++++++++-- FS/FS/cust_main.pm | 2 +- httemplate/edit/cust_main/billing.html | 7 +++++++ httemplate/view/cust_main/billing.html | 7 +++++++ 6 files changed, 53 insertions(+), 3 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 20abd4546..40fbaf6c5 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2168,6 +2168,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'voip-cust_email_csv_cdr', + 'section' => '', + 'description' => 'Enable the per-customer option for including CDR information as a CSV attachment on emailed invoices.', + 'type' => 'checkbox', + }, + { 'key' => 'svc_forward-arbitrary_dst', 'section' => '', diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index b2f590aec..649e0aa49 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -698,6 +698,7 @@ sub tables_hashref { 'cdr_termination_percentage', 'decimal', 'NULL', '', '', '', 'invoice_terms', 'varchar', 'NULL', $char_d, '', '', 'archived', 'char', 'NULL', 1, '', '', + 'email_csv_cdr', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'custnum', 'unique' => [ [ 'agentnum', 'agent_custid' ] ], diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 9937bc76d..4e28af39c 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -704,6 +704,18 @@ sub generate_email { #'Filename' => 'invoice.pdf', ); + my @otherparts = (); + if ( $self->cust_main->email_csv_cdr ) { + + push @otherparts, build MIME::Entity + 'Type' => 'text/csv', + 'Encoding' => '7bit', + 'Data' => [ map { "$_\n" } $self->call_details ], + 'Disposition' => 'attachment', + ; + + } + if ( $conf->exists('invoice_email_pdf') ) { #attaching pdf too: @@ -731,7 +743,7 @@ sub generate_email { my $pdf = build MIME::Entity $self->mimebuild_pdf('', $args{'template'}, %cdrs); - $return{'mimeparts'} = [ $related, $pdf ]; + $return{'mimeparts'} = [ $related, $pdf, @otherparts ]; } else { @@ -743,7 +755,7 @@ sub generate_email { # image/png $return{'content-type'} = 'multipart/related'; - $return{'mimeparts'} = [ $alternative, $image ]; + $return{'mimeparts'} = [ $alternative, $image, @otherparts ]; $return{'type'} = 'multipart/alternative'; #Content-Type of first part... #$return{'disposition'} = 'inline'; @@ -3033,6 +3045,22 @@ sub _items_payments { } +=item call_details + +Returns an array of CSV strings representing the call details for this invoice + +=cut + +sub call_details { + my $self = shift; + map { $_->details( 'format_function' => sub{ shift }, + 'escape_function' => sub{ return() }, + ) + } + grep { $_->pkgnum } + $self->cust_bill_pkg; +} + =back diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 518ab4d98..f6ac186f9 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1869,7 +1869,7 @@ sub check { $self->payname($1); } - foreach my $flag (qw( tax spool_cdr squelch_cdr archived )) { + foreach my $flag (qw( tax spool_cdr squelch_cdr archived email_csv_cdr )) { $self->$flag() =~ /^(Y?)$/ or return "Illegal $flag: ". $self->$flag(); $self->$flag($1); } diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index 3f3d80176..363dd0419 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -438,6 +438,13 @@ % } +% if ( $conf->exists('voip-cust_email_csv_cdr') ) { + + email_csv_cdr eq "Y" ? 'CHECKED' : '' %>> Attach CDRs as CSV to emailed invoices + +% } else { + +% } % if ( $show_term || $cust_main->cdr_termination_percentage ) { diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html index 049461dbd..c8d0c47cd 100644 --- a/httemplate/view/cust_main/billing.html +++ b/httemplate/view/cust_main/billing.html @@ -216,6 +216,13 @@ Billing information % } +% if ( $conf->exists('voip-cust_email_csv_cdr') ) { + + Email CDRs as CSV + <% $cust_main->email_csv_cdr ? 'yes' : 'no' %> + +% } + % if ( $show_term || $cust_main->cdr_termination_percentage ) { CDR termination settlement -- cgit v1.2.1 From 4396080ed2829ae0595f1fd777f39d090c9bcd7c Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 06:42:33 +0000 Subject: experimental package balances, RT#4339 --- FS/FS/Conf.pm | 7 + FS/FS/Schema.pm | 6 + FS/FS/cust_bill.pm | 104 ++++++++++-- FS/FS/cust_bill_ApplicationCommon.pm | 4 + FS/FS/cust_bill_pay.pm | 2 + FS/FS/cust_credit.pm | 6 + FS/FS/cust_credit_bill.pm | 2 + FS/FS/cust_main.pm | 179 +++++++++++++++++++-- FS/FS/cust_pay.pm | 50 ++++-- FS/FS/cust_pay_pending.pm | 6 + FS/FS/cust_pay_void.pm | 38 ++++- FS/FS/cust_pkg.pm | 57 +++++++ httemplate/edit/cust_credit.cgi | 13 ++ httemplate/edit/cust_pay.cgi | 14 +- httemplate/edit/process/cust_pay.cgi | 4 +- httemplate/elements/select-cust_pkg-balances.html | 30 ++++ .../elements/tr-select-cust_pkg-balances.html | 31 ++++ httemplate/view/cust_bill.cgi | 1 + httemplate/view/cust_main/packages.html | 3 + httemplate/view/cust_main/packages/status.html | 43 +++-- httemplate/view/cust_main/payment_history.html | 13 +- .../view/cust_main/payment_history/credit.html | 14 +- .../view/cust_main/payment_history/payment.html | 14 +- .../cust_main/payment_history/voided_payment.html | 5 + httemplate/view/cust_pay.html | 9 ++ 25 files changed, 586 insertions(+), 69 deletions(-) create mode 100644 httemplate/elements/select-cust_pkg-balances.html create mode 100644 httemplate/elements/tr-select-cust_pkg-balances.html diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 40fbaf6c5..c335c0140 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -3009,6 +3009,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'pkg-balances', + 'section' => 'billing', + 'description' => 'Enable experimental package balances. Not recommended for general use.', + 'type' => 'checkbox', + }, + { key => "apacheroot", section => "deprecated", description => "DEPRECATED", type => "text" }, { key => "apachemachine", section => "deprecated", description => "DEPRECATED", type => "text" }, { key => "apachemachines", section => "deprecated", description => "DEPRECATED", type => "text" }, diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 649e0aa49..15adba3ed 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -598,6 +598,7 @@ sub tables_hashref { 'reasonnum', 'int', 'NULL', '', '', '', 'addlinfo', 'text', 'NULL', '', '', '', 'closed', 'char', 'NULL', 1, '', '', + 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances ], 'primary_key' => 'crednum', 'unique' => [], @@ -611,6 +612,7 @@ sub tables_hashref { 'invnum', 'int', '', '', '', '', '_date', @date_type, '', '', 'amount', @money_type, '', '', + 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances ], 'primary_key' => 'creditbillnum', 'unique' => [], @@ -941,6 +943,7 @@ sub tables_hashref { #'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes. 'payunique', 'varchar', 'NULL', $char_d, '', '', #separate paybatch "unique" functions from current usage + 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances 'status', 'varchar', '', $char_d, '', '', 'session_id', 'varchar', 'NULL', $char_d, '', '', #only need 32 'statustext', 'text', 'NULL', '', '', '', @@ -970,6 +973,7 @@ sub tables_hashref { 'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes. 'payunique', 'varchar', 'NULL', $char_d, '', '', #separate paybatch "unique" functions from current usage 'closed', 'char', 'NULL', 1, '', '', + 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances ], 'primary_key' => 'paynum', #i guess not now, with cust_pay_pending, if we actually make it here, we _do_ want to record it# 'unique' => [ [ 'payunique' ] ], @@ -989,6 +993,7 @@ sub tables_hashref { 'paymask', 'varchar', 'NULL', $char_d, '', '', 'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes. 'closed', 'char', 'NULL', 1, '', '', + 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances 'void_date', @date_type, '', '', 'reason', 'varchar', 'NULL', $char_d, '', '', 'otaker', 'varchar', '', 32, '', '', @@ -1005,6 +1010,7 @@ sub tables_hashref { 'paynum', 'int', '', '', '', '', 'amount', @money_type, '', '', '_date', @date_type, '', '', + 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances ], 'primary_key' => 'billpaynum', 'unique' => [], diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 4e28af39c..4acdd85a3 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -235,6 +235,25 @@ sub cust_bill_pkg { ); } +=item cust_bill_pkg_pkgnum PKGNUM + +Returns the line items (see L) for this invoice and +specified pkgnum. + +=cut + +sub cust_bill_pkg_pkgnum { + my( $self, $pkgnum ) = @_; + qsearch( + { 'table' => 'cust_bill_pkg', + 'hashref' => { 'invnum' => $self->invnum, + 'pkgnum' => $pkgnum, + }, + 'order_by' => 'ORDER BY billpkgnum', + } + ); +} + =item cust_pkg Returns the packages (see L) corresponding to the line items for @@ -432,6 +451,38 @@ sub cust_credited { ; } +=item cust_bill_pay_pkgnum + +Returns all payment applications (see L) for this invoice +with matching pkgnum. + +=cut + +sub cust_bill_pay_pkgnum { + my( $self, $pkgnum ) = @_; + sort { $a->_date <=> $b->_date } + qsearch( 'cust_bill_pay', { 'invnum' => $self->invnum, + 'pkgnum' => $pkgnum, + } + ); +} + +=item cust_credited_pkgnum + +Returns all applied credits (see L) for this invoice +with matching pkgnum. + +=cut + +sub cust_credited_pkgnum { + my( $self, $pkgnum ) = @_; + sort { $a->_date <=> $b->_date } + qsearch( 'cust_credit_bill', { 'invnum' => $self->invnum, + 'pkgnum' => $pkgnum, + } + ); +} + =item tax Returns the tax amount (see L) for this invoice. @@ -465,6 +516,21 @@ sub owed { $balance; } +sub owed_pkgnum { + my( $self, $pkgnum ) = @_; + + #my $balance = $self->charged; + my $balance = 0; + $balance += $_->setup + $_->recur for $self->cust_bill_pkg_pkgnum($pkgnum); + + $balance -= $_->amount for $self->cust_bill_pay_pkgnum($pkgnum); + $balance -= $_->amount for $self->cust_credited_pkgnum($pkgnum); + + $balance = sprintf( "%.2f", $balance); + $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp + $balance; +} + =item apply_payments_and_credits =cut @@ -488,6 +554,13 @@ sub apply_payments_and_credits { my @payments = grep { $_->unapplied > 0 } $self->cust_main->cust_pay; my @credits = grep { $_->credited > 0 } $self->cust_main->cust_credit; + if ( $conf->exists('pkg-balances') ) { + # limit @payments & @credits to those w/ a pkgnum grepped from $self + my %pkgnums = map { $_ => 1 } map $_->pkgnum, $self->cust_bill_pkg; + @payments = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @payments; + @credits = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @credits; + } + while ( $self->owed > 0 and ( @payments || @credits ) ) { my $app = ''; @@ -525,28 +598,39 @@ sub apply_payments_and_credits { die "guru meditation #12 and 35"; } + my $unapp_amount; if ( $app eq 'pay' ) { my $payment = shift @payments; - - $app = new FS::cust_bill_pay { - 'paynum' => $payment->paynum, - 'amount' => sprintf('%.2f', min( $payment->unapplied, $self->owed ) ), - }; + $unapp_amount = $payment->unapplied; + $app = new FS::cust_bill_pay { 'paynum' => $payment->paynum }; + $app->pkgnum( $payment->pkgnum ) + if $conf->exists('pkg-balances') && $payment->pkgnum; } elsif ( $app eq 'credit' ) { my $credit = shift @credits; - - $app = new FS::cust_credit_bill { - 'crednum' => $credit->crednum, - 'amount' => sprintf('%.2f', min( $credit->credited, $self->owed ) ), - }; + $unapp_amount = $credit->credited; + $app = new FS::cust_credit_bill { 'crednum' => $credit->crednum }; + $app->pkgnum( $credit->pkgnum ) + if $conf->exists('pkg-balances') && $credit->pkgnum; } else { die "guru meditation #12 and 35"; } + my $owed; + if ( $conf->exists('pkg-balances') && $app->pkgnum ) { + warn "owed_pkgnum ". $app->pkgnum; + $owed = $self->owed_pkgnum($app->pkgnum); + } else { + $owed = $self->owed; + } + next unless $owed > 0; + + warn "min ( $unapp_amount, $owed )\n"; + $app->amount( sprintf('%.2f', min( $unapp_amount, $owed ) ) ); + $app->invnum( $self->invnum ); my $error = $app->insert; diff --git a/FS/FS/cust_bill_ApplicationCommon.pm b/FS/FS/cust_bill_ApplicationCommon.pm index af7e0879e..ec694ca58 100644 --- a/FS/FS/cust_bill_ApplicationCommon.pm +++ b/FS/FS/cust_bill_ApplicationCommon.pm @@ -115,6 +115,8 @@ sub apply_to_lineitems { my @apply = (); + my $conf = new FS::Conf; + local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; local $SIG{QUIT} = 'IGNORE'; @@ -127,6 +129,8 @@ sub apply_to_lineitems { my $dbh = dbh; my @open = $self->cust_bill->open_cust_bill_pkg; #FOR UPDATE...? + @open = grep { $_->pkgnum == $self->pkgnum } @open + if $conf->exists('pkg-balances') && $self->pkgnum; warn "$me ". scalar(@open). " open line items for invoice ". $self->cust_bill->invnum. ": ". join(', ', @open). "\n" if $DEBUG; diff --git a/FS/FS/cust_bill_pay.pm b/FS/FS/cust_bill_pay.pm index b7ba2b711..e1b02aecb 100644 --- a/FS/FS/cust_bill_pay.pm +++ b/FS/FS/cust_bill_pay.pm @@ -7,6 +7,7 @@ use FS::cust_main_Mixin; use FS::cust_bill_ApplicationCommon; use FS::cust_bill; use FS::cust_pay; +use FS::cust_pkg; @ISA = qw( FS::cust_main_Mixin FS::cust_bill_ApplicationCommon ); @@ -121,6 +122,7 @@ sub check { || $self->ut_foreign_key('invnum', 'cust_bill', 'invnum' ) || $self->ut_numbern('_date') || $self->ut_money('amount') + || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') ; return $error if $error; diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm index 47a8119ee..6c3effa13 100644 --- a/FS/FS/cust_credit.pm +++ b/FS/FS/cust_credit.pm @@ -8,6 +8,7 @@ use FS::Misc qw(send_email); use FS::Record qw( qsearch qsearchs dbdef ); use FS::cust_main_Mixin; use FS::cust_main; +use FS::cust_pkg; use FS::cust_refund; use FS::cust_credit_bill; use FS::part_pkg; @@ -95,6 +96,10 @@ Text Books closed flag, empty or `Y' +=item pkgnum + +Desired pkgnum when using experimental package balances. + =back =head1 METHODS @@ -295,6 +300,7 @@ sub check { || $self->ut_foreign_key('reasonnum', 'reason', 'reasonnum') || $self->ut_textn('addlinfo') || $self->ut_enum('closed', [ '', 'Y' ]) + || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') ; return $error if $error; diff --git a/FS/FS/cust_credit_bill.pm b/FS/FS/cust_credit_bill.pm index 375c885a0..900a5c0d5 100644 --- a/FS/FS/cust_credit_bill.pm +++ b/FS/FS/cust_credit_bill.pm @@ -8,6 +8,7 @@ use FS::cust_main_Mixin; use FS::cust_bill_ApplicationCommon; use FS::cust_bill; use FS::cust_credit; +use FS::cust_pkg; @ISA = qw( FS::cust_main_Mixin FS::cust_bill_ApplicationCommon ); @@ -122,6 +123,7 @@ sub check { || $self->ut_foreign_key('invnum', 'cust_bill', 'invnum' ) || $self->ut_numbern('_date') || $self->ut_money('amount') + || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') ; return $error if $error; diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index f6ac186f9..9c131744d 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -6110,32 +6110,52 @@ sub apply_credits { @invoices = sort { $b->_date <=> $a->_date } @invoices if defined($opt{'order'}) && $opt{'order'} eq 'newest'; + if ( $conf->exists('pkg-balances') ) { + # limit @credits to those w/ a pkgnum grepped from $self + my %pkgnums = (); + foreach my $i (@invoices) { + foreach my $li ( $i->cust_bill_pkg ) { + $pkgnums{$li->pkgnum} = 1; + } + } + @credits = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @credits; + } + my $credit; + foreach my $cust_bill ( @invoices ) { - my $amount; if ( !defined($credit) || $credit->credited == 0) { $credit = pop @credits or last; } - if ($cust_bill->owed >= $credit->credited) { - $amount=$credit->credited; - }else{ - $amount=$cust_bill->owed; + my $owed; + if ( $conf->exists('pkg-balances') && $credit->pkgnum ) { + $owed = $cust_bill->owed_pkgnum($credit->pkgnum); + } else { + $owed = $cust_bill->owed; + } + unless ( $owed > 0 ) { + push @credits, $credit; + next; } + + my $amount = min( $credit->credited, $owed ); my $cust_credit_bill = new FS::cust_credit_bill ( { 'crednum' => $credit->crednum, 'invnum' => $cust_bill->invnum, 'amount' => $amount, } ); + $cust_credit_bill->pkgnum( $credit->pkgnum ) + if $conf->exists('pkg-balances') && $credit->pkgnum; my $error = $cust_credit_bill->insert; if ( $error ) { $dbh->rollback or die $dbh->errstr if $oldAutoCommit; die $error; } - redo if ($cust_bill->owed > 0); + redo if ($cust_bill->owed > 0) && ! $conf->exists('pkg-balances'); } @@ -6183,33 +6203,52 @@ sub apply_payments { grep { $_->owed > 0 } $self->cust_bill; + if ( $conf->exists('pkg-balances') ) { + # limit @payments to those w/ a pkgnum grepped from $self + my %pkgnums = (); + foreach my $i (@invoices) { + foreach my $li ( $i->cust_bill_pkg ) { + $pkgnums{$li->pkgnum} = 1; + } + } + @payments = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @payments; + } + my $payment; foreach my $cust_bill ( @invoices ) { - my $amount; if ( !defined($payment) || $payment->unapplied == 0 ) { $payment = pop @payments or last; } - if ( $cust_bill->owed >= $payment->unapplied ) { - $amount = $payment->unapplied; + my $owed; + if ( $conf->exists('pkg-balances') && $payment->pkgnum ) { + $owed = $cust_bill->owed_pkgnum($payment->pkgnum); } else { - $amount = $cust_bill->owed; + $owed = $cust_bill->owed; } + unless ( $owed > 0 ) { + push @payments, $payment; + next; + } + + my $amount = min( $payment->unapplied, $owed ); my $cust_bill_pay = new FS::cust_bill_pay ( { 'paynum' => $payment->paynum, 'invnum' => $cust_bill->invnum, 'amount' => $amount, } ); + $cust_bill_pay->pkgnum( $payment->pkgnum ) + if $conf->exists('pkg-balances') && $payment->pkgnum; my $error = $cust_bill_pay->insert; if ( $error ) { $dbh->rollback or die $dbh->errstr if $oldAutoCommit; die $error; } - redo if ( $cust_bill->owed > 0); + redo if ( $cust_bill->owed > 0) && ! $conf->exists('pkg-balances'); } @@ -6270,6 +6309,41 @@ sub total_owed_date { } +=item total_owed_pkgnum PKGNUM + +Returns the total owed on all invoices for this customer's specific package +when using experimental package balances (see L). + +=cut + +sub total_owed_pkgnum { + my( $self, $pkgnum ) = @_; + $self->total_owed_date_pkgnum(2145859200, $pkgnum); #12/31/2037 +} + +=item total_owed_date_pkgnum TIME PKGNUM + +Returns the total owed for this customer's specific package when using +experimental package balances on all invoices with date earlier than +TIME. TIME is specified as a UNIX timestamp; see L). Also +see L and L for conversion functions. + +=cut + +sub total_owed_date_pkgnum { + my( $self, $time, $pkgnum ) = @_; + + my $total_bill = 0; + foreach my $cust_bill ( + grep { $_->_date <= $time } + qsearch('cust_bill', { 'custnum' => $self->custnum, } ) + ) { + $total_bill += $cust_bill->owed_pkgnum($pkgnum); + } + sprintf( "%.2f", $total_bill ); + +} + =item total_paid Returns the total amount of all payments. @@ -6306,6 +6380,21 @@ sub total_unapplied_credits { sprintf( "%.2f", $total_credit ); } +=item total_unapplied_credits_pkgnum PKGNUM + +Returns the total outstanding credit (see L) for this +customer. See L. + +=cut + +sub total_unapplied_credits_pkgnum { + my( $self, $pkgnum ) = @_; + my $total_credit = 0; + $total_credit += $_->credited foreach $self->cust_credit_pkgnum($pkgnum); + sprintf( "%.2f", $total_credit ); +} + + =item total_unapplied_payments Returns the total unapplied payments (see L) for this customer. @@ -6320,6 +6409,22 @@ sub total_unapplied_payments { sprintf( "%.2f", $total_unapplied ); } +=item total_unapplied_payments_pkgnum PKGNUM + +Returns the total unapplied payments (see L) for this customer's +specific package when using experimental package balances. See +L. + +=cut + +sub total_unapplied_payments_pkgnum { + my( $self, $pkgnum ) = @_; + my $total_unapplied = 0; + $total_unapplied += $_->unapplied foreach $self->cust_pay_pkgnum($pkgnum); + sprintf( "%.2f", $total_unapplied ); +} + + =item total_unapplied_refunds Returns the total unrefunded refunds (see L) for this @@ -6372,6 +6477,26 @@ sub balance_date { ); } +=item balance_pkgnum PKGNUM + +Returns the balance for this customer's specific package when using +experimental package balances (total_owed plus total_unrefunded, minus +total_unapplied_credits minus total_unapplied_payments) + +=cut + +sub balance_pkgnum { + my( $self, $pkgnum ) = @_; + + sprintf( "%.2f", + $self->total_owed_pkgnum($pkgnum) +# n/a - refunds aren't part of pkg-balances since they don't apply to invoices +# + $self->total_unapplied_refunds_pkgnum($pkgnum) + - $self->total_unapplied_credits_pkgnum($pkgnum) + - $self->total_unapplied_payments_pkgnum($pkgnum) + ); +} + =item in_transit_payments Returns the total of requests for payments for this customer pending in @@ -7001,6 +7126,22 @@ sub cust_credit { qsearch( 'cust_credit', { 'custnum' => $self->custnum } ) } +=item cust_credit_pkgnum + +Returns all the credits (see L) for this customer's specific +package when using experimental package balances. + +=cut + +sub cust_credit_pkgnum { + my( $self, $pkgnum ) = @_; + sort { $a->_date <=> $b->_date } + qsearch( 'cust_credit', { 'custnum' => $self->custnum, + 'pkgnum' => $pkgnum, + } + ); +} + =item cust_pay Returns all the payments (see L) for this customer. @@ -7013,6 +7154,22 @@ sub cust_pay { qsearch( 'cust_pay', { 'custnum' => $self->custnum } ) } +=item cust_pay_pkgnum + +Returns all the payments (see L) for this customer's specific +package when using experimental package balances. + +=cut + +sub cust_pay_pkgnum { + my( $self, $pkgnum ) = @_; + sort { $a->_date <=> $b->_date } + qsearch( 'cust_pay', { 'custnum' => $self->custnum, + 'pkgnum' => $pkgnum, + } + ); +} + =item cust_pay_void Returns all voided payments (see L) for this customer. diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 4ff291934..e1e6df2a2 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -17,6 +17,7 @@ use FS::cust_bill; use FS::cust_bill_pay; use FS::cust_pay_refund; use FS::cust_main; +use FS::cust_pkg; use FS::cust_pay_void; @ISA = qw( FS::payinfo_transaction_Mixin FS::cust_main_Mixin FS::Record ); @@ -62,28 +63,54 @@ currently supported: =over 4 -=item paynum - primary key (assigned automatically for new payments) +=item paynum -=item custnum - customer (see L) +primary key (assigned automatically for new payments) -=item _date - specified as a UNIX timestamp; see L. Also see +=item custnum + +customer (see L) + +=item _date + +specified as a UNIX timestamp; see L. Also see L and L for conversion functions. -=item paid - Amount of this payment +=item paid + +Amount of this payment + +=item otaker + +order taker (assigned automatically, see L) + +=item payby + +Payment Type (See L for valid payby values) + +=item payinfo + +Payment Information (See L for data format) + +=item paymask + +Masked payinfo (See L for how this works) + +=item paybatch -=item otaker - order taker (assigned automatically, see L) +text field for tracking card processing or other batch grouping -=item payby - Payment Type (See L for valid payby values) +=item payunique -=item payinfo - Payment Information (See L for data format) +Optional unique identifer to prevent duplicate transactions. -=item paymask - Masked payinfo (See L for how this works) +=item closed -=item paybatch - text field for tracking card processing or other batch grouping +books closed flag, empty or `Y' -=item payunique - Optional unique identifer to prevent duplicate transactions. +=item pkgnum -=item closed - books closed flag, empty or `Y' +Desired pkgnum when using experimental package balances. =back @@ -417,6 +444,7 @@ sub check { || $self->ut_textn('paybatch') || $self->ut_textn('payunique') || $self->ut_enum('closed', [ '', 'Y' ]) + || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') || $self->payinfo_check() ; return $error if $error; diff --git a/FS/FS/cust_pay_pending.pm b/FS/FS/cust_pay_pending.pm index fba19ea19..f48e1a8c1 100644 --- a/FS/FS/cust_pay_pending.pm +++ b/FS/FS/cust_pay_pending.pm @@ -6,6 +6,7 @@ use FS::Record qw( qsearch qsearchs dbh ); #dbh for _upgrade_data use FS::payinfo_transaction_Mixin; use FS::cust_main_Mixin; use FS::cust_main; +use FS::cust_pkg; use FS::cust_pay; @ISA = qw( FS::payinfo_transaction_Mixin FS::cust_main_Mixin FS::Record ); @@ -77,6 +78,10 @@ Expiration date Unique identifer to prevent duplicate transactions. +=item pkgnum + +Desired pkgnum when using experimental package balances. + =item status Pending transaction status, one of the following: @@ -193,6 +198,7 @@ sub check { #|| $self->ut_money('cust_balance') || $self->ut_hexn('session_id') || $self->ut_foreign_keyn('paynum', 'cust_pay', 'paynum' ) + || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') || $self->payinfo_check() #payby/payinfo/paymask/paydate ; return $error if $error; diff --git a/FS/FS/cust_pay_void.pm b/FS/FS/cust_pay_void.pm index de05f710b..86fbbe5ab 100644 --- a/FS/FS/cust_pay_void.pm +++ b/FS/FS/cust_pay_void.pm @@ -9,6 +9,7 @@ use FS::cust_pay; #use FS::cust_bill_pay; #use FS::cust_pay_refund; #use FS::cust_main; +use FS::cust_pkg; @ISA = qw( FS::Record FS::payinfo_Mixin ); @@ -40,24 +41,44 @@ are currently supported: =over 4 -=item paynum - primary key (assigned automatically for new payments) +=item paynum -=item custnum - customer (see L) +primary key (assigned automatically for new payments) -=item paid - Amount of this payment +=item custnum -=item _date - specified as a UNIX timestamp; see L. Also see +customer (see L) + +=item paid + +Amount of this payment + +=item _date + +specified as a UNIX timestamp; see L. Also see L and L for conversion functions. -=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH), +=item payby + +`CARD' (credit cards), `CHEK' (electronic check/ACH), `LECB' (phone bill billing), `BILL' (billing), `CASH' (cash), `WEST' (Western Union), `MCRD' (Manual credit card), or `COMP' (free) -=item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively +=item payinfo + +card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively + +=item paybatch + +text field for tracking card processing + +=item closed + +books closed flag, empty or `Y' -=item paybatch - text field for tracking card processing +=item pkgnum -=item closed - books closed flag, empty or `Y' +Desired pkgnum when using experimental package balances. =item void_date @@ -156,6 +177,7 @@ sub check { || $self->ut_number('_date') || $self->ut_textn('paybatch') || $self->ut_enum('closed', [ '', 'Y' ]) + || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum') || $self->ut_numbern('void_date') || $self->ut_textn('reason') ; diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 00a030117..4724514c0 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1750,6 +1750,63 @@ sub statuscolor { $statuscolor{$self->status}; } +=item pkg_label + +Returns a label for this package. (Currently "pkgnum: pkg - comment" or +"pkg-comment" depending on user preference). + +=cut + +sub pkg_label { + my $self = shift; + my $label = $self->part_pkg->pkg_comment( 'nopkgpart' => 1 ); + $label = $self->pkgnum. ": $label" + if $FS::CurrentUser::CurrentUser->option('show_pkgnum'); + $label; +} + +=item pkg_label_long + +Returns a long label for this package, adding the primary service's label to +pkg_label. + +=cut + +sub pkg_label_long { + my $self = shift; + my $label = $self->pkg_label; + my $cust_svc = $self->primary_cust_svc; + $label .= ' ('. ($cust_svc->label)[1]. ')' if $cust_svc; + $label; +} + +=item primary_cust_svc + +Returns a primary service (as FS::cust_svc object) if one can be identified. + +=cut + +#for labeling purposes - might not 100% match up with part_pkg->svcpart's idea + +sub primary_cust_svc { + my $self = shift; + + my @cust_svc = $self->cust_svc; + + return '' unless @cust_svc; #no serivces - irrelevant then + + return $cust_svc[0] if scalar(@cust_svc) == 1; #always return a single service + + # primary service as specified in the package definition + # or exactly one service definition with quantity one + my $svcpart = $self->part_pkg->svcpart; + @cust_svc = grep { $_->svcpart == $svcpart } @cust_svc; + return $cust_svc[0] if scalar(@cust_svc) == 1; + + #couldn't identify one thing.. + return ''; +} + =item labels Returns a list of lists, calling the label method for all services diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi index c9ca31ff3..c6b2bcbea 100755 --- a/httemplate/edit/cust_credit.cgi +++ b/httemplate/edit/cust_credit.cgi @@ -40,6 +40,16 @@ Credit +% if ( $conf->exists('pkg-balances') ) { + <% include('/elements/tr-select-cust_pkg-balances.html', + 'custnum' => $custnum, + 'cgi' => $cgi + ) + %> +% } else { + +% } +
@@ -65,4 +75,7 @@ my $_date = time; my $otaker = getotaker; my $p1 = popurl(1); +my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die "unknown custnum $custnum\n"; + diff --git a/httemplate/edit/cust_pay.cgi b/httemplate/edit/cust_pay.cgi index 3c2877498..4dff06d88 100755 --- a/httemplate/edit/cust_pay.cgi +++ b/httemplate/edit/cust_pay.cgi @@ -72,6 +72,16 @@ Payment % } +% if ( $conf->exists('pkg-balances') ) { + <% include('/elements/tr-select-cust_pkg-balances.html', + 'custnum' => $custnum, + 'cgi' => $cgi + ) + %> +% } else { + +% } +
@@ -95,7 +105,7 @@ my $money_char = $conf->config('money_char') || '$'; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Post payment'); -my($link, $linknum, $paid, $payby, $payinfo, $_date); +my($link, $linknum, $paid, $payby, $payinfo, $_date, $pkgnum); if ( $cgi->param('error') ) { $link = $cgi->param('link'); $linknum = $cgi->param('linknum'); @@ -131,7 +141,7 @@ if ( $link eq 'invnum' ) { my $cust_bill = qsearchs('cust_bill', { 'invnum' => $linknum } ) or die "unknown invnum $linknum"; $custnum = $cust_bill->custnum; -} elsif ( $link eq 'custnum' ) { +} elsif ( $link eq 'custnum' || $link eq 'popup' ) { $custnum = $linknum; } diff --git a/httemplate/edit/process/cust_pay.cgi b/httemplate/edit/process/cust_pay.cgi index 647f6fc6c..f8ac8b183 100755 --- a/httemplate/edit/process/cust_pay.cgi +++ b/httemplate/edit/process/cust_pay.cgi @@ -46,7 +46,9 @@ my $new = new FS::cust_pay ( { _date => $_date, map { $_, scalar($cgi->param($_)); - } qw(paid payby payinfo paybatch) + } qw( paid payby payinfo paybatch + pkgnum + ) #} fields('cust_pay') } ); diff --git a/httemplate/elements/select-cust_pkg-balances.html b/httemplate/elements/select-cust_pkg-balances.html new file mode 100644 index 000000000..d41bd033e --- /dev/null +++ b/httemplate/elements/select-cust_pkg-balances.html @@ -0,0 +1,30 @@ + +<%init> + +my %opt = @_; + +my @cust_pkg; +if ( $opt{'cust_pkg'} ) { + + @cust_pkg = @{ $opt{'cust_pkg'} }; + +} else { + + my $custnum = $opt{'custnum'}; + + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die "unknown custnum $custnum\n"; + + @cust_pkg = + grep { ! $_->get('cancel') || $cust_main->balance_pkgnum($_->pkgnum) } + $cust_main->all_pkgs; + +} + + diff --git a/httemplate/elements/tr-select-cust_pkg-balances.html b/httemplate/elements/tr-select-cust_pkg-balances.html new file mode 100644 index 000000000..89dc5d415 --- /dev/null +++ b/httemplate/elements/tr-select-cust_pkg-balances.html @@ -0,0 +1,31 @@ +% if ( scalar(@cust_pkg) == 0 ) { + +% } elsif ( scalar(@cust_pkg) == 1 ) { + +% } else { + + For package + + <% include('select-cust_pkg-balances.html', + 'cust_pkg' => \@cust_pkg, + 'cgi' => $opt{'cgi'}, + ) + %> + + + +% } + +<%init> +my %opt = @_; + +my $custnum = $opt{'custnum'}; + +my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die "unknown custnum $custnum\n"; + +my @cust_pkg = + grep { ! $_->get('cancel') || $cust_main->balance_pkgnum($_->pkgnum) } + $cust_main->all_pkgs; + + diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi index 450c74e61..2673e8239 100755 --- a/httemplate/view/cust_bill.cgi +++ b/httemplate/view/cust_bill.cgi @@ -6,6 +6,7 @@ % if ( $cust_bill->owed > 0 % && scalar( grep $payby{$_}, qw(BILL CASH WEST MCRD) ) % && $FS::CurrentUser::CurrentUser->access_right('Post payment') +% && ! $conf->exists('pkg-balances') % ) % { % my $s = 0; diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 428794b7d..8fbefae50 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -138,6 +138,9 @@ my %conf_opt = ( #for status.html 'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'), + #for status.html pkg-balances + 'pkg-balances' => $conf->exists('pkg-balances'), + 'money_char' => ( $conf->config('money_char') || '$' ), #for location.html 'countrydefault' => $countrydefault, diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html index 6daff5031..f3b2faaf4 100644 --- a/httemplate/view/cust_main/packages/status.html +++ b/httemplate/view/cust_main/packages/status.html @@ -8,15 +8,16 @@ <% pkg_status_row($cust_pkg, 'Cancelled', 'cancel', 'color'=>'FF0000', %opt ) %> - <% pkg_status_row_colspan( + <% pkg_status_row_colspan( $cust_pkg, ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '', 'align'=>'right', 'color'=>'ff0000', 'size'=>'-2', 'colspan'=>$colspan, + %opt ) %> % unless ( $cust_pkg->get('setup') ) { - <% pkg_status_row_colspan('Never billed', '', 'colspan'=>$colspan, ) %> + <% pkg_status_row_colspan( $cust_pkg, 'Never billed', '', 'colspan'=>$colspan, %opt, ) %> % } else { @@ -34,14 +35,15 @@ <% pkg_status_row( $cust_pkg, 'Suspended', 'susp', 'color'=>'FF9900', %opt ) %> - <% pkg_status_row_colspan( + <% pkg_status_row_colspan( $cust_pkg, ( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '', 'align'=>'right', 'color'=>'FF9900', 'size'=>'-2', 'colspan'=>$colspan, + %opt, ) %> % unless ( $cust_pkg->get('setup') ) { - <% pkg_status_row_colspan('Never billed', '', 'colspan'=>$colspan ) %> + <% pkg_status_row_colspan( $cust_pkg, 'Never billed', '', 'colspan'=>$colspan, %opt ) %> % } else { <% pkg_status_row($cust_pkg, 'Setup', 'setup', %opt ) %> % } @@ -70,7 +72,7 @@ % % unless ( $part_pkg->freq ) { - <% pkg_status_row_colspan('Not yet billed (one-time charge)', '', 'colspan'=>$colspan, ) %> + <% pkg_status_row_colspan( $cust_pkg, 'Not yet billed (one-time charge)', '', 'colspan'=>$colspan, %opt ) %> <% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %> @@ -86,7 +88,7 @@ % } else { - <% pkg_status_row_colspan("Not yet billed ($billed_or_prepaid ". myfreq($part_pkg). ')', '', 'colspan'=>$colspan ) %> + <% pkg_status_row_colspan($cust_pkg, "Not yet billed ($billed_or_prepaid ". myfreq($part_pkg). ')', '', 'colspan'=>$colspan, %opt ) %> <% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %> @@ -96,7 +98,7 @@ % % unless ( $part_pkg->freq ) { - <% pkg_status_row_colspan('One-time charge', '', 'colspan'=>$colspan, ) %> + <% pkg_status_row_colspan($cust_pkg, 'One-time charge', '', 'colspan'=>$colspan, %opt ) %> <% pkg_status_row($cust_pkg, 'Billed', 'setup', %opt) %> @@ -104,18 +106,20 @@ % % if (scalar($cust_pkg->overlimit)) { - <% pkg_status_row_colspan( + <% pkg_status_row_colspan( $cust_pkg, 'Overlimit', $billed_or_prepaid. ' '. myfreq($part_pkg), 'color'=>'FFD000', 'colspan'=>$colspan, + %opt ) %> % } else { - <% pkg_status_row_colspan( + <% pkg_status_row_colspan( $cust_pkg, 'Active', $billed_or_prepaid. ' '. myfreq($part_pkg), 'color'=>'00CC00', 'colspan'=>$colspan, + %opt ) %> % } @@ -169,7 +173,6 @@ - <%init> my %opt = @_; @@ -218,8 +221,15 @@ sub pkg_status_row { $html .= qq() if length($color); $html .= qq($title ); $html .= qq() if length($color); + + if ( $opt{'pkg_balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge + $html .= ' (Balance: '. $opt{'money_char'}. + $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum). + ')'; + } + $html .= qq(); - $html .= pkg_datestr($cust_pkg, $field, %opt).''; + $html .= pkg_datestr($cust_pkg, $field, %opt). ''; $html; } @@ -253,7 +263,7 @@ sub pkg_status_row_changed { my $part_pkg = $old->part_pkg; my $label = 'Changed from '. $cust_pkg->change_pkgnum. ': '. $part_pkg->pkg_comment(nopartpkg => 1); - $html .= pkg_status_row_colspan( $label, '', + $html .= pkg_status_row_colspan( $cust_pkg, $label, '', 'size' => '-1', 'align' => 'right', 'colspan' => $opt{'colspan'}, @@ -264,7 +274,7 @@ sub pkg_status_row_changed { } sub pkg_status_row_colspan { - my($title, $addl, %opt) = @_; + my($cust_pkg, $title, $addl, %opt) = @_; my $colspan = $opt{'colspan'}; @@ -279,6 +289,13 @@ sub pkg_status_row_colspan { $html .= qq(
) if $color && !$size; $html .= qq(
) if length($color) || $size; $html .= ", $addl" if length($addl); + + if ( $opt{'pkg-balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge + $html .= ' (Balance: '. $opt{'money_char'}. + $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum). + ')'; + } + $html .= qq(); $html; diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html index 1711e1449..8adc95426 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -374,13 +374,16 @@ my %status = ( #get payment history my @history = (); -my %opt = +my %opt = ( ( map { $_ => scalar($conf->config($_)) } qw( card_refund-days ) ), ( map { $_ => $conf->exists($_) } - qw( deletepayments deleterefunds ) - ); + qw( deletepayments deleterefunds pkg-balances ) + ) +); + +warn Dumper(\%opt); #invoices foreach my $cust_bill ($cust_main->cust_bill) { @@ -405,7 +408,7 @@ foreach my $cust_pay ($cust_main->cust_pay) { foreach my $cust_pay_void ($cust_main->cust_pay_void) { push @history, { 'date' => $cust_pay_void->_date, - 'desc' => include('payment_history/voided_payment.html', $cust_pay_void), + 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ), 'void_payment' => $cust_pay_void->paid, }; @@ -415,7 +418,7 @@ foreach my $cust_pay_void ($cust_main->cust_pay_void) { foreach my $cust_credit ($cust_main->cust_credit) { push @history, { 'date' => $cust_credit->_date, - 'desc' => include('payment_history/credit.html', $cust_credit), + 'desc' => include('payment_history/credit.html', $cust_credit, %opt ), 'credit' => $cust_credit->amount, }; diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html index 2deb27564..058c6f536 100644 --- a/httemplate/view/cust_main/payment_history/credit.html +++ b/httemplate/view/cust_main/payment_history/credit.html @@ -9,7 +9,13 @@ my $curuser = $FS::CurrentUser::CurrentUser; my @cust_credit_bill = $cust_credit->cust_credit_bill; my @cust_credit_refund = $cust_credit->cust_credit_refund; -my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' ); +my $desc = ''; +if ( $opt{'pkg-balances'} && $cust_credit->pkgnum ) { + my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_credit->pkgnum } ); + $desc .= ' for '. $cust_pkg->pkg_label_long; +} + +my( $pre, $post, $apply, $ext ) = ( '', '', '', '' ); if ( scalar(@cust_credit_bill) == 0 && scalar(@cust_credit_refund) == 0 ) { #completely unapplied @@ -45,15 +51,15 @@ if ( scalar(@cust_credit_bill) == 0 && scalar(@cust_credit_refund) == 0 && $cust_credit->credited == 0 ) { #applied to one invoice, the usual situation - $desc = ' '. $cust_credit_bill[0]->applied_to_invoice; + $desc .= ' '. $cust_credit_bill[0]->applied_to_invoice; } elsif ( scalar(@cust_credit_bill) == 0 && scalar(@cust_credit_refund) == 1 && $cust_credit->credited == 0 ) { #applied to one refund - $desc = ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date); + $desc .= ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date); } else { #complicated - $desc = '
'; + $desc .= '
'; foreach my $app ( sort { $a->_date <=> $b->_date } ( @cust_credit_bill, @cust_credit_refund ) ) { if ( $app->isa('FS::cust_credit_bill') ) { diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html index 2e24b1785..a4a349bb8 100644 --- a/httemplate/view/cust_main/payment_history/payment.html +++ b/httemplate/view/cust_main/payment_history/payment.html @@ -32,7 +32,13 @@ $payby =~ s/^MCRD$/Manual credit card/; $payby =~ s/^BILL$//; my $info = $payby ? "($payby$payinfo)" : ''; -my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' ); +my $desc = ''; +if ( $opt{'pkg-balances'} && $cust_pay->pkgnum ) { + my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay->pkgnum } ); + $desc .= ' for '. $cust_pkg->pkg_label_long; +} + +my( $pre, $post, $apply, $ext ) = ( '', '', '', '' ); if ( scalar(@cust_bill_pay) == 0 && scalar(@cust_pay_refund) == 0 ) { #completely unapplied @@ -68,15 +74,15 @@ if ( scalar(@cust_bill_pay) == 0 && scalar(@cust_pay_refund) == 0 && $cust_pay->unapplied == 0 ) { #applied to one invoice, the usual situation - $desc = ' '. $cust_bill_pay[0]->applied_to_invoice; + $desc .= ' '. $cust_bill_pay[0]->applied_to_invoice; } elsif ( scalar(@cust_bill_pay) == 0 && scalar(@cust_pay_refund) == 1 && $cust_pay->unapplied == 0 ) { #applied to one refund - $desc = ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date); + $desc .= ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date); } else { #complicated - $desc = '
'; + $desc .= '
'; foreach my $app ( sort { $a->_date <=> $b->_date } ( @cust_bill_pay, @cust_pay_refund ) ) { if ( $app->isa('FS::cust_bill_pay') ) { diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html index 9cbc47b66..08469dbe9 100644 --- a/httemplate/view/cust_main/payment_history/voided_payment.html +++ b/httemplate/view/cust_main/payment_history/voided_payment.html @@ -18,6 +18,11 @@ $payby =~ s/^BILL$//; $payby =~ s/^(CARD|COMP)$/$1 /; my $info = $payby ? " ($payby$payinfo)" : ''; +if ( $opt{'pkg-balances'} && $cust_pay_void->pkgnum ) { + my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay_void->pkgnum } ); + $info .= ' for '. $cust_pkg->pkg_label_long; +} + my $unvoid = ''; if ( $cust_pay_void->closed !~ /^Y/i && $curuser->access_right('Unvoid') diff --git a/httemplate/view/cust_pay.html b/httemplate/view/cust_pay.html index a5c99ac55..2f23d9e14 100644 --- a/httemplate/view/cust_pay.html +++ b/httemplate/view/cust_pay.html @@ -93,6 +93,15 @@ % } +% if ( $conf->exists('pkg-balances') && $cust_pay->pkgnum ) { +% my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay->pkgnum } ); + + For package + <% $cust_pkg->pkg_label_long %> + + +% } + % if ( $link eq 'print' ) { -- cgit v1.2.1 From 111fd2db1424182903285e92a957f6f036cb58ce Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 06:48:07 +0000 Subject: fix for stickiness on errors --- httemplate/elements/select-cust_pkg-balances.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/httemplate/elements/select-cust_pkg-balances.html b/httemplate/elements/select-cust_pkg-balances.html index d41bd033e..cd2e1a850 100644 --- a/httemplate/elements/select-cust_pkg-balances.html +++ b/httemplate/elements/select-cust_pkg-balances.html @@ -9,6 +9,8 @@ my %opt = @_; +my $cgi = $opt{'cgi'}; + my @cust_pkg; if ( $opt{'cust_pkg'} ) { -- cgit v1.2.1 From 3bd6725beea327a3ce72cfd13bf79fac87e36665 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 06:49:17 +0000 Subject: don't need to lookup cust_main here --- httemplate/edit/cust_credit.cgi | 3 --- 1 file changed, 3 deletions(-) diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi index c6b2bcbea..5785a05c0 100755 --- a/httemplate/edit/cust_credit.cgi +++ b/httemplate/edit/cust_credit.cgi @@ -75,7 +75,4 @@ my $_date = time; my $otaker = getotaker; my $p1 = popurl(1); -my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) - or die "unknown custnum $custnum\n"; - -- cgit v1.2.1 From f43362b2ee2e56b238fcae935a31b552b51506ba Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 06:50:29 +0000 Subject: another accidentally (alliterated) vestigial variable --- httemplate/edit/cust_pay.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/cust_pay.cgi b/httemplate/edit/cust_pay.cgi index 4dff06d88..07e51989e 100755 --- a/httemplate/edit/cust_pay.cgi +++ b/httemplate/edit/cust_pay.cgi @@ -105,7 +105,7 @@ my $money_char = $conf->config('money_char') || '$'; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Post payment'); -my($link, $linknum, $paid, $payby, $payinfo, $_date, $pkgnum); +my($link, $linknum, $paid, $payby, $payinfo, $_date); if ( $cgi->param('error') ) { $link = $cgi->param('link'); $linknum = $cgi->param('linknum'); -- cgit v1.2.1 From da635762c054395a44145362f1ddd2ccdbb87416 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 06:52:16 +0000 Subject: didn't mean to leave a Dump(er) there --- httemplate/view/cust_main/payment_history.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html index 8adc95426..24af5c9a5 100644 --- a/httemplate/view/cust_main/payment_history.html +++ b/httemplate/view/cust_main/payment_history.html @@ -383,8 +383,6 @@ my %opt = ( ) ); -warn Dumper(\%opt); - #invoices foreach my $cust_bill ($cust_main->cust_bill) { push @history, { -- cgit v1.2.1 From 57c08db01160c72aaada973a62f7b3a2e3cbd544 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 30 Jul 2009 07:35:18 +0000 Subject: Make no_queue option work correctly --- FS/FS/part_export/shellcommands.pm | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm index e375302a4..11e3b7d4b 100644 --- a/FS/FS/part_export/shellcommands.pm +++ b/FS/FS/part_export/shellcommands.pm @@ -301,13 +301,23 @@ sub _export_command { $ldap_password = shell_quote $ldap_password; my $command_string = eval(qq("$command")); - - $self->shellcommands_queue( $svc_acct->svcnum, - user => $self->option('user')||'root', - host => $self->machine, - command => $command_string, - stdin_string => $stdin_string, + my @ssh_cmd_args = ( + user => $self->option('user') || 'root', + host => $self->machine, + command => $command_string, + stdin_string => $stdin_string, ); + + if($self->options('no_queue')) { + # discard return value just like freeside-queued. + eval { ssh_cmd(@ssh_cmd_args) }; + $error = $@; + return $error. ' ('. $self->exporttype. ' to '. $self->machine. ')' + if $error; + } + else { + $self->shellcommands_queue( $new->svcnum, @ssh_cmd_args ); + } } sub _export_replace { -- cgit v1.2.1 From 32e1fac180b972b037d36f4496566eaf7c6079c6 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 07:39:17 +0000 Subject: small fix to change history to not error out with svc_acct services, RT#1005 --- httemplate/view/cust_main/change_history.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/view/cust_main/change_history.html b/httemplate/view/cust_main/change_history.html index 1700bc34b..53a79f47f 100644 --- a/httemplate/view/cust_main/change_history.html +++ b/httemplate/view/cust_main/change_history.html @@ -202,7 +202,7 @@ my $pkg_labelsub = sub { my $svc_labelsub = sub { my($item, $label) = @_; - $label. ': '. encode_entities($item->label). ''; + $label. ': '. encode_entities($item->label($item->history_date)). ''; }; my %h_table_labelsub = ( -- cgit v1.2.1 From 72a60ae400c253e913728a830e588e209b1a23fe Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 08:43:45 +0000 Subject: lost fix for illegal state? --- fs_selfservice/FS-SelfService/cgi/selfservice.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index 148fc4ddc..ed1e6a190 100644 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -366,7 +366,7 @@ sub payment_results { $cgi->param('city') =~ /^(.{0,80})$/ or die "illegal city"; my $city = $1; - $cgi->param('state') =~ /^(.{80})$/ or die "illegal state"; + $cgi->param('state') =~ /^(.{0,80})$/ or die "illegal state"; my $state = $1; $cgi->param('zip') =~ /^(.{0,10})$/ or die "illegal zip"; -- cgit v1.2.1 From c1dbb54da9699d6d347b6d8392e2108f80fb1dcf Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 30 Jul 2009 09:19:20 +0000 Subject: pass a pkgnum from self-service if applicable, RT#4339 --- FS/FS/ClientAPI/MyAccount.pm | 11 ++++++++--- FS/FS/cust_main.pm | 6 +++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 02b54ffc9..895b11d9d 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -128,6 +128,8 @@ sub login { if ( $cust_pkg ) { my $cust_main = $cust_pkg->cust_main; $session->{'custnum'} = $cust_main->custnum; + $session->{'pkgnum'} = $cust_pkg->pkgnum + if $conf->exists('pkg-balances'); } my $session_id; @@ -518,6 +520,7 @@ sub process_payment { 'payname' => $payname, 'paybatch' => $paybatch, #this doesn't actually do anything 'paycvv' => $paycvv, + 'pkgnum' => $session->{'pkgnum'}, map { $_ => $p->{$_} } @{ $payby2fields{$payby} } ); return { 'error' => $error } if $error; @@ -560,9 +563,11 @@ sub realtime_collect { my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; - my $error = $cust_main->realtime_collect( 'method' => $p->{'method'}, - 'session_id' => $p->{'session_id'}, - ); + my $error = $cust_main->realtime_collect( + 'method' => $p->{'method'}, + 'pkgnum' => $session->{'pkgnum'}, + 'session_id' => $p->{'session_id'}, + ); return { 'error' => $error } unless ref( $error ); return { 'error' => '', amount => $cust_main->balance, %$error }; diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 9c131744d..becb9054b 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3961,6 +3961,7 @@ sub realtime_bop { 'payinfo' => $payinfo, 'paydate' => $paydate, 'recurring_billing' => $content{recurring_billing}, + 'pkgnum' => $options{'pkgnum'}, 'status' => 'new', 'gatewaynum' => ( $payment_gateway ? $payment_gateway->gatewaynum : '' ), }; @@ -4116,6 +4117,7 @@ sub realtime_bop { 'payinfo' => $payinfo, 'paybatch' => $paybatch, 'paydate' => $paydate, + 'pkgnum' => $options{'pkgnum'}, } ); #doesn't hurt to know, even though the dup check is in cust_pay_pending now $cust_pay->payunique( $options{payunique} ) @@ -4629,7 +4631,7 @@ On failure returns an error message. Returns false or a hashref upon success. The hashref contains keys popup_url reference, and collectitems. The first is a URL to which a browser should be redirected for completion of collection. The second is a reference id for the transaction suitable for the end user. The collectitems is a reference to a list of name value pairs suitable for assigning to a html form and posted to popup_url. -Available options are: I, I, I, I, I, I, I, I +Available options are: I, I, I, I, I, I, I, I, I I is one of: I, I and I. If none is specified then it is deduced from the customer record. @@ -5002,6 +5004,7 @@ sub _new_realtime_bop { 'payinfo' => $options{payinfo}, 'paydate' => $paydate, 'recurring_billing' => $content{recurring_billing}, + 'pkgnum' => $options{'pkgnum'}, 'status' => 'new', 'gatewaynum' => $payment_gateway->gatewaynum || '', 'session_id' => $options{session_id} || '', @@ -5248,6 +5251,7 @@ sub _realtime_bop_result { #'payinfo' => $payinfo, 'paybatch' => $paybatch, 'paydate' => $cust_pay_pending->paydate, + 'pkgnum' => $cust_pay_pending->pkgnum, } ); #doesn't hurt to know, even though the dup check is in cust_pay_pending now $cust_pay->payunique( $options{payunique} ) -- cgit v1.2.1 From 6b3ae185f5fcd3b884cbd9d15cf408d4821bb34e Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 31 Jul 2009 07:51:55 +0000 Subject: only need Customer-CDRs, RT#5229 --- bin/cdr-transnexus.import | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/cdr-transnexus.import b/bin/cdr-transnexus.import index ee9a200dc..10e0aed52 100755 --- a/bin/cdr-transnexus.import +++ b/bin/cdr-transnexus.import @@ -50,7 +50,8 @@ foreach my $dir ( @$lsdir ) { my $dirname = $dir->{filename}; warn "Scanning dir $dirname\n" if $opt_v; - my $ls = $ls_sftp->ls("$DIR/$dirname", wanted => qr/^$opt_p.*-CDRs$/i ); + #my $ls = $ls_sftp->ls("$DIR/$dirname", wanted => qr/^$opt_p.*-CDRs$/i ); + my $ls = $ls_sftp->ls("$DIR/$dirname", wanted => qr/^$opt_p.*-Customer-CDRs$/i ); foreach my $file ( @$ls ) { -- cgit v1.2.1 From 124b91bedc8e815956b3d0440414a8c0e6a5b78b Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 31 Jul 2009 07:58:04 +0000 Subject: only need Customer-CDRs, RT#5229 --- bin/cdr-transnexus.import | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cdr-transnexus.import b/bin/cdr-transnexus.import index 10e0aed52..9686f7d2f 100755 --- a/bin/cdr-transnexus.import +++ b/bin/cdr-transnexus.import @@ -51,7 +51,7 @@ foreach my $dir ( @$lsdir ) { warn "Scanning dir $dirname\n" if $opt_v; #my $ls = $ls_sftp->ls("$DIR/$dirname", wanted => qr/^$opt_p.*-CDRs$/i ); - my $ls = $ls_sftp->ls("$DIR/$dirname", wanted => qr/^$opt_p.*-Customer-CDRs$/i ); + my $ls = $ls_sftp->ls("$DIR/$dirname", wanted => qr/^$opt_p.*Customer-CDRs$/i ); foreach my $file ( @$ls ) { -- cgit v1.2.1 From 7f43bf155bc79e3c9bd5d88e53117595963c301e Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 31 Jul 2009 13:20:54 +0000 Subject: skin up self-service according to config passed from backend, RT#5530 --- FS/FS/ClientAPI/MyAccount.pm | 19 +++++++++++++++++++ fs_selfservice/FS-SelfService/SelfService.pm | 1 + .../FS-SelfService/cgi/ach_payment_results.html | 8 +++----- fs_selfservice/FS-SelfService/cgi/change_bill.html | 9 +++------ .../FS-SelfService/cgi/change_password.html | 7 ++----- fs_selfservice/FS-SelfService/cgi/change_pay.html | 21 +++------------------ fs_selfservice/FS-SelfService/cgi/change_ship.html | 9 +++------ .../FS-SelfService/cgi/customer_change_pkg.html | 8 +++----- .../FS-SelfService/cgi/customer_order_pkg.html | 8 +++----- fs_selfservice/FS-SelfService/cgi/delete_svc.html | 7 ++----- fs_selfservice/FS-SelfService/cgi/footer.html | 4 ++-- fs_selfservice/FS-SelfService/cgi/header.html | 20 +++++++++++++++++--- fs_selfservice/FS-SelfService/cgi/login.html | 19 ++++++++++++++----- fs_selfservice/FS-SelfService/cgi/logout.html | 14 +++++++++++--- .../FS-SelfService/cgi/make_ach_payment.html | 21 +++------------------ .../FS-SelfService/cgi/make_payment.html | 21 +++------------------ fs_selfservice/FS-SelfService/cgi/myaccount.html | 6 +----- .../FS-SelfService/cgi/myaccount_menu.html | 4 ++-- .../FS-SelfService/cgi/payment_results.html | 8 +++----- .../FS-SelfService/cgi/process_change_bill.html | 6 +----- .../cgi/process_change_password.html | 6 +----- .../FS-SelfService/cgi/process_change_pay.html | 6 +----- .../FS-SelfService/cgi/process_change_pkg.html | 6 +----- .../FS-SelfService/cgi/process_change_ship.html | 6 +----- .../FS-SelfService/cgi/process_order_pkg.html | 6 +----- .../FS-SelfService/cgi/process_order_recharge.html | 6 +----- .../FS-SelfService/cgi/process_svc_acct.html | 6 +----- fs_selfservice/FS-SelfService/cgi/provision.html | 8 +++----- .../FS-SelfService/cgi/provision_svc_acct.html | 8 +++----- .../FS-SelfService/cgi/recharge_prepay.html | 8 +++----- .../FS-SelfService/cgi/recharge_results.html | 8 +++----- fs_selfservice/FS-SelfService/cgi/selfservice.cgi | 22 ++++++++++++---------- .../FS-SelfService/cgi/view_invoice.html | 6 +----- .../FS-SelfService/cgi/view_usage_details.html | 6 +----- 34 files changed, 132 insertions(+), 196 deletions(-) diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 895b11d9d..9d031be33 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -55,6 +55,25 @@ sub _cache { } ); } +sub skin_info { + #my $p = shift; + + my $conf = new FS::Conf; + + my %skin = ( + 'head' => join("\n", $conf->config('selfservice-head') ), + 'body_header' => join("\n", $conf->config('selfservice-body_header') ), + 'body_footer' => join("\n", $conf->config('selfservice-body_footer') ), + 'body_bgcolor' => scalar( $conf->config('selfservice-body_bgcolor') ), + 'box_bgcolor' => scalar( $conf->config('selfservice-box_bgcolor') ), + + 'company_name' => scalar($conf->config('company_name')), + ); + + \%skin; + +} + sub login_info { my $p = shift; diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index 322782a3f..d275fa86d 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -60,6 +60,7 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'unprovision_svc' => 'MyAccount/unprovision_svc', 'myaccount_passwd' => 'MyAccount/myaccount_passwd', 'signup_info' => 'Signup/signup_info', + 'skin_info' => 'MyAccount/skin_info', 'domain_select_hash' => 'Signup/domain_select_hash', # expose? 'new_customer' => 'Signup/new_customer', 'capture_payment' => 'Signup/capture_payment', diff --git a/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html b/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html index 62419d152..987b97efb 100644 --- a/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html +++ b/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html @@ -1,13 +1,11 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + Payment results

<%= if ( $error ) { $OUT .= qq!Error processing your payment: $error!; } else { $OUT .= 'Your payment was processed successfully. Thank you.'; } %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/change_bill.html b/fs_selfservice/FS-SelfService/cgi/change_bill.html index f186c9b51..c0977d946 100755 --- a/fs_selfservice/FS-SelfService/cgi/change_bill.html +++ b/fs_selfservice/FS-SelfService/cgi/change_bill.html @@ -1,9 +1,6 @@ -MyAccount - -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + Edit billing address

<%= if ( $error ) { $OUT .= qq!Error: $error

!; @@ -19,5 +16,5 @@ ">
- + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/change_password.html b/fs_selfservice/FS-SelfService/cgi/change_password.html index dcfce3173..9b91d2cad 100644 --- a/fs_selfservice/FS-SelfService/cgi/change_password.html +++ b/fs_selfservice/FS-SelfService/cgi/change_password.html @@ -1,8 +1,5 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Change password

@@ -47,5 +44,5 @@ - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/change_pay.html b/fs_selfservice/FS-SelfService/cgi/change_pay.html index 7283cb850..e7a996931 100644 --- a/fs_selfservice/FS-SelfService/cgi/change_pay.html +++ b/fs_selfservice/FS-SelfService/cgi/change_pay.html @@ -1,21 +1,6 @@ -MyAccount - - -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + Change payment information

<%= if ( $error ) { $OUT .= qq!Error: $error

!; @@ -70,5 +55,5 @@ )->html; %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/change_ship.html b/fs_selfservice/FS-SelfService/cgi/change_ship.html index 28ee94ed6..f03aeb5be 100755 --- a/fs_selfservice/FS-SelfService/cgi/change_ship.html +++ b/fs_selfservice/FS-SelfService/cgi/change_ship.html @@ -1,9 +1,6 @@ -MyAccount - -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + Edit service address

<%= if ( $error ) { $OUT .= qq!Error: $error

!; @@ -98,5 +95,5 @@ function samechanged(what) { ">
- + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html b/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html index 46d3faf86..95bdab76c 100644 --- a/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html @@ -1,8 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + <%= include('change_pkg') %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html b/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html index 78cc16c27..a20e8acbc 100755 --- a/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html @@ -1,8 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + <%= include('order_pkg') %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/delete_svc.html b/fs_selfservice/FS-SelfService/cgi/delete_svc.html index 4155d09cf..e16b01eea 100644 --- a/fs_selfservice/FS-SelfService/cgi/delete_svc.html +++ b/fs_selfservice/FS-SelfService/cgi/delete_svc.html @@ -1,8 +1,5 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> <%= if ( $error ) { $OUT .= qq!Error: $error!; @@ -10,5 +7,5 @@ $OUT .= "$svc removed."; } %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/footer.html b/fs_selfservice/FS-SelfService/cgi/footer.html index 98cc79b74..4889b741a 100644 --- a/fs_selfservice/FS-SelfService/cgi/footer.html +++ b/fs_selfservice/FS-SelfService/cgi/footer.html @@ -1,3 +1,3 @@ -
-powered by freeside + +<%= $body_footer %> diff --git a/fs_selfservice/FS-SelfService/cgi/header.html b/fs_selfservice/FS-SelfService/cgi/header.html index cf8fd2bd9..630959e33 100644 --- a/fs_selfservice/FS-SelfService/cgi/header.html +++ b/fs_selfservice/FS-SelfService/cgi/header.html @@ -1,9 +1,23 @@ - MyAccount + <%= $title || 'MyAccount' %> + <%= $head %> - - MyAccount + + + <%= $body_header %> + <%= $title || 'MyAccount' %>

<%= include('myaccount_menu') %> diff --git a/fs_selfservice/FS-SelfService/cgi/login.html b/fs_selfservice/FS-SelfService/cgi/login.html index e5daec859..760f579bb 100644 --- a/fs_selfservice/FS-SelfService/cgi/login.html +++ b/fs_selfservice/FS-SelfService/cgi/login.html @@ -1,11 +1,18 @@ -Login -Login

+ + + Login + <%= $head %> + + + <%= $body_header %> + +Login

<%= $error %>
- +
@@ -50,13 +57,15 @@ if ( $single_domain ) { if ( $phone_login ) { + $box_bgcolor ||= '#c0c0c0'; + $OUT .= qq( OR

-
Username
+
Phone number @@ -82,4 +91,4 @@ if ( $phone_login ) { %> - +<%= $body_footer %> diff --git a/fs_selfservice/FS-SelfService/cgi/logout.html b/fs_selfservice/FS-SelfService/cgi/logout.html index 0e774e9eb..e2de648ce 100644 --- a/fs_selfservice/FS-SelfService/cgi/logout.html +++ b/fs_selfservice/FS-SelfService/cgi/logout.html @@ -1,5 +1,13 @@ -MyAccount -MyAccount

+ + + MyAccount + <%= $head %> + + + <%= $body_header %> + + MyAccount

You have been logged out. - + +<%= $body_footer %> diff --git a/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html b/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html index 2394c10d4..8802a5d97 100644 --- a/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html @@ -1,21 +1,6 @@ -MyAccount - - -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> -
+<%= include('header') %> + Make a payment

@@ -54,5 +39,5 @@ -
+ <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/make_payment.html b/fs_selfservice/FS-SelfService/cgi/make_payment.html index da6e67ed2..96a17ba4c 100644 --- a/fs_selfservice/FS-SelfService/cgi/make_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/make_payment.html @@ -1,21 +1,6 @@ -MyAccount - - -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + Make a payment

@@ -64,5 +49,5 @@
- + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html index c9ca0c5f0..bcfcf9540 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html @@ -1,8 +1,5 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Hello <%= $name %>!

<%= $small_custview %> @@ -94,5 +91,4 @@ Hello <%= $name %>!

} %> - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html index cc9f255ce..5cf4fe2d9 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html @@ -1,6 +1,6 @@ <%= $url = "$selfurl?session=$session_id;action="; ''; %> -
+ @@ -74,7 +74,7 @@ foreach my $item ( @menu ) { $OUT .= '{'url'} && $action eq $item->{'url'} ) { - $OUT .= ' BGCOLOR="#eeeeee" '. + $OUT .= ' BGCOLOR="'. ( $body_bgcolor || '#eeeeee' ). '" '. ' STYLE="border-top: 1px solid black;'. ' border-left: 1px solid black;'. ' border-bottom: 1px solid black"'; diff --git a/fs_selfservice/FS-SelfService/cgi/payment_results.html b/fs_selfservice/FS-SelfService/cgi/payment_results.html index 62419d152..987b97efb 100644 --- a/fs_selfservice/FS-SelfService/cgi/payment_results.html +++ b/fs_selfservice/FS-SelfService/cgi/payment_results.html @@ -1,13 +1,11 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> -
+<%= include('header') %> + Payment results

<%= if ( $error ) { $OUT .= qq!Error processing your payment: $error!; } else { $OUT .= 'Your payment was processed successfully. Thank you.'; } %> -
+ <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_bill.html b/fs_selfservice/FS-SelfService/cgi/process_change_bill.html index 93e05cf7f..a4402848d 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_bill.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_bill.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> -
+<%= include('header') %> Information updated successfully. -
<%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_password.html b/fs_selfservice/FS-SelfService/cgi/process_change_password.html index bfd23127c..ffe0cab35 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_password.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_password.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Password changed for <%= $value %> <%= $label %>. - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_pay.html b/fs_selfservice/FS-SelfService/cgi/process_change_pay.html index 93e05cf7f..a4402848d 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_pay.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_pay.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Information updated successfully. - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html b/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html index 7c0f0a6ca..c7c69f0a5 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Package change successful. - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_ship.html b/fs_selfservice/FS-SelfService/cgi/process_change_ship.html index 93e05cf7f..a4402848d 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_change_ship.html +++ b/fs_selfservice/FS-SelfService/cgi/process_change_ship.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Information updated successfully. - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html b/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html index 3e4471d33..b86893715 100755 --- a/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html +++ b/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Package order successful. - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html b/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html index ef0516ac9..9dfc32807 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html +++ b/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> <%= $svc %> recharged successfully. - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html index 813521fda..39920cb0d 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html +++ b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> <%= $svc %> setup successfully. - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/provision.html b/fs_selfservice/FS-SelfService/cgi/provision.html index 5ae7b42b7..f5b2c2b71 100644 --- a/fs_selfservice/FS-SelfService/cgi/provision.html +++ b/fs_selfservice/FS-SelfService/cgi/provision.html @@ -1,8 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + <%= include('provision_list') %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html index 550493bbc..bffd22fd1 100644 --- a/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html +++ b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html @@ -1,8 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + <%= include('svc_acct') %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html b/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html index 3de4c8790..6f0aa1f62 100644 --- a/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html +++ b/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html @@ -1,8 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + Recharge with prepaid card

@@ -29,5 +27,5 @@
- + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/recharge_results.html b/fs_selfservice/FS-SelfService/cgi/recharge_results.html index 6d928e3f9..af15365b0 100644 --- a/fs_selfservice/FS-SelfService/cgi/recharge_results.html +++ b/fs_selfservice/FS-SelfService/cgi/recharge_results.html @@ -1,8 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> + Recharge results

<%= if ( $error ) { $OUT .= qq!Error processing your prepaid card: $error!; @@ -17,5 +15,5 @@ $OUT .= 'Thank you.'; } %> - + <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index ed1e6a190..09cfe6073 100644 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -9,16 +9,15 @@ use Text::Template; use HTML::Entities; use Date::Format; use Number::Format 1.50; -use FS::SelfService qw( login_info login customer_info edit_info invoice - payment_info process_payment realtime_collect - process_prepay - list_pkgs order_pkg signup_info order_recharge - part_svc_info provision_acct provision_external - unprovision_svc change_pkg domainselector - list_svcs - list_svc_usage list_cdr_usage list_support_usage - myaccount_passwd - ); +use FS::SelfService qw( + skin_info login_info login customer_info edit_info invoice + payment_info process_payment realtime_collect process_prepay + list_pkgs order_pkg signup_info order_recharge + part_svc_info provision_acct provision_external + unprovision_svc change_pkg domainselector + list_svcs list_svc_usage list_cdr_usage list_support_usage + myaccount_passwd +); $template_dir = '.'; @@ -646,6 +645,9 @@ sub do_template { $fill_in->{'selfurl'} = $cgi->self_url; $fill_in->{'cgi'} = \$cgi; + my $skin_info = skin_info(); + $fill_in->{$_} = $skin_info->{$_} foreach keys %$skin_info; + my $source = "$template_dir/$name.html"; #warn "creating template for $source\n"; my $template = new Text::Template( TYPE => 'FILE', diff --git a/fs_selfservice/FS-SelfService/cgi/view_invoice.html b/fs_selfservice/FS-SelfService/cgi/view_invoice.html index 8fa5fb7dc..8a1c1c73d 100644 --- a/fs_selfservice/FS-SelfService/cgi/view_invoice.html +++ b/fs_selfservice/FS-SelfService/cgi/view_invoice.html @@ -1,10 +1,6 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> <%= $invoice_html %> - <%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/view_usage_details.html b/fs_selfservice/FS-SelfService/cgi/view_usage_details.html index 6bac7487c..9f02eba79 100644 --- a/fs_selfservice/FS-SelfService/cgi/view_usage_details.html +++ b/fs_selfservice/FS-SelfService/cgi/view_usage_details.html @@ -1,8 +1,5 @@ -MyAccount -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> Service usage details for <%= Date::Format::time2str('%b %o %Y', $beginning) %> - @@ -80,5 +77,4 @@
- <%= include('footer') %> -- cgit v1.2.1 From 9f64bfef652922b7b546a12290805710acbeed08 Mon Sep 17 00:00:00 2001 From: jeff Date: Sat, 1 Aug 2009 19:16:47 +0000 Subject: support broader array of queue args #5855, fallout from #5495 --- FS/FS/Schema.pm | 1 + FS/FS/queue.pm | 17 +++++++++++------ FS/FS/queue_arg.pm | 3 +++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 15adba3ed..80aed8297 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1622,6 +1622,7 @@ sub tables_hashref { 'columns' => [ 'argnum', 'serial', '', '', '', '', 'jobnum', 'int', '', '', '', '', + 'frozen', 'char', 'NULL', 1, '', '', 'arg', 'text', 'NULL', '', '', '', ], 'primary_key' => 'argnum', diff --git a/FS/FS/queue.pm b/FS/FS/queue.pm index 381e418c9..1f2abe3ae 100644 --- a/FS/FS/queue.pm +++ b/FS/FS/queue.pm @@ -3,6 +3,8 @@ package FS::queue; use strict; use vars qw( @ISA @EXPORT_OK $DEBUG $conf $jobnums); use Exporter; +use MIME::Base64; +use Storable qw( nfreeze thaw ); use FS::UID qw(myconnect); use FS::Conf; use FS::Record qw( qsearch qsearchs dbh ); @@ -142,9 +144,11 @@ sub insert { } foreach my $arg ( @args ) { + my $freeze = ref($arg) ? 'Y' : ''; my $queue_arg = new FS::queue_arg ( { 'jobnum' => $self->jobnum, - 'arg' => $arg, + 'frozen' => $freeze, + 'arg' => $freeze ? encode_base64(nfreeze($arg)) : $arg,# always freeze? } ); $error = $queue_arg->insert; if ( $error ) { @@ -254,11 +258,12 @@ Returns a list of the arguments associated with this job. sub args { my $self = shift; - map $_->arg, qsearch( 'queue_arg', - { 'jobnum' => $self->jobnum }, - '', - 'ORDER BY argnum' - ); + map { $_->frozen ? thaw(decode_base64($_->arg)) : $_->arg } + qsearch( 'queue_arg', + { 'jobnum' => $self->jobnum }, + '', + 'ORDER BY argnum' + ); } =item cust_svc diff --git a/FS/FS/queue_arg.pm b/FS/FS/queue_arg.pm index c96ff1236..8e9a10d28 100644 --- a/FS/FS/queue_arg.pm +++ b/FS/FS/queue_arg.pm @@ -36,6 +36,8 @@ FS::Record. The following fields are currently supported: =item jobnum - see L +=item frozen - argument is frozen with Storable + =item arg - argument =back @@ -96,6 +98,7 @@ sub check { my $error = $self->ut_numbern('argnum') || $self->ut_numbern('jobnum') + || $self->ut_enum('frozen', [ '', 'Y' ]) || $self->ut_anything('arg') ; return $error if $error; -- cgit v1.2.1 From 01b857aa5fb209905d569844bc44710999df84e6 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 3 Aug 2009 14:07:27 +0000 Subject: bad tyops --- FS/FS/part_export/shellcommands.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm index 11e3b7d4b..faf065593 100644 --- a/FS/FS/part_export/shellcommands.pm +++ b/FS/FS/part_export/shellcommands.pm @@ -308,7 +308,7 @@ sub _export_command { stdin_string => $stdin_string, ); - if($self->options('no_queue')) { + if($self->option('no_queue')) { # discard return value just like freeside-queued. eval { ssh_cmd(@ssh_cmd_args) }; $error = $@; @@ -387,7 +387,7 @@ sub _export_replace { stdin_string => $stdin_string, ); - if($self->options('no_queue')) { + if($self->option('no_queue')) { # discard return value just like freeside-queued. eval { ssh_cmd(@ssh_cmd_args) }; $error = $@; -- cgit v1.2.1 From 3ad071d4c8d05a8a0a1e5a975722600e183548b4 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 3 Aug 2009 14:17:15 +0000 Subject: new doesn't exist --- FS/FS/part_export/shellcommands.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm index faf065593..ed51f5d72 100644 --- a/FS/FS/part_export/shellcommands.pm +++ b/FS/FS/part_export/shellcommands.pm @@ -316,7 +316,7 @@ sub _export_command { if $error; } else { - $self->shellcommands_queue( $new->svcnum, @ssh_cmd_args ); + $self->shellcommands_queue( $svc_acct->svcnum, @ssh_cmd_args ); } } -- cgit v1.2.1 From 6e80cdbaa7fc1f5a8247d19aceeb652844352207 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 3 Aug 2009 19:54:00 +0000 Subject: looks slightly better in default IE hopefully --- httemplate/elements/header.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html index 8adfabc93..54383bc27 100644 --- a/httemplate/elements/header.html +++ b/httemplate/elements/header.html @@ -174,7 +174,7 @@ input.fstext { % if ( $curuser->access_right('List customers') ) {
-
+
Advanced
@@ -201,7 +201,7 @@ input.fstext { Adv % }
- + % } @@ -209,7 +209,7 @@ input.fstext { % if ( $curuser->access_right('View customer services') ) {
-
+
Advanced
@@ -219,7 +219,7 @@ input.fstext { % if ( $conf->config("ticket_system") ) {
-
+
Advanced
-- cgit v1.2.1 From 32c4b823d2561ec9ed14fa446c11f15a68404d37 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 4 Aug 2009 00:19:23 +0000 Subject: don't reset usage on package change when usage_rollover is on, it adds twice... --- FS/FS/cust_pkg.pm | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 4724514c0..396ae07cc 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -1188,13 +1188,14 @@ sub change { } #reset usage if changing pkgpart + # AND usage rollover is off (otherwise adds twice, now and at package bill) if ($self->pkgpart != $cust_pkg->pkgpart) { my $part_pkg = $cust_pkg->part_pkg; $error = $part_pkg->reset_usage($cust_pkg, $part_pkg->is_prepaid ? () : ( 'null' => 1 ) ) - if $part_pkg->can('reset_usage'); + if $part_pkg->can('reset_usage') && ! $part_pkg->option('usage_rollover'); if ($error) { $dbh->rollback if $oldAutoCommit; @@ -1835,6 +1836,19 @@ sub h_labels { map { [ $_->label(@_) ] } $self->h_cust_svc(@_); } +=item labels_short + +Like labels, except returns a simple flat list, and shortens long +(currently >5 or the cust_bill-max_same_services configuration value) lists of +identical services to one line that lists the service label and the number of +individual services rather than individual items. + +=cut + +sub labels_short { + shift->_labels_short( 'labels', @_ ); +} + =item h_labels_short END_TIMESTAMP [ START_TIMESTAMP ] Like h_labels, except returns a simple flat list, and shortens long @@ -1845,7 +1859,11 @@ individual services rather than individual items. =cut sub h_labels_short { - my $self = shift; + shift->_labels_short( 'h_labels', @_ ); +} + +sub _labels_short { + my( $self, $method ) = ( shift, shift ); my $conf = new FS::Conf; my $max_same_services = $conf->config('cust_bill-max_same_services') || 5; -- cgit v1.2.1 From de7dc370b95f4175dd3119acffe2af2c8f6d735f Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 4 Aug 2009 22:04:51 +0000 Subject: ignore problams calling ->overlimit during sqlradius-reset, wtf?! RT#5868 --- FS/FS/svc_Common.pm | 21 ++++++++++++++++++--- FS/bin/freeside-sqlradius-reset | 4 ++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/FS/FS/svc_Common.pm b/FS/FS/svc_Common.pm index 869ab5831..8fd5d0df6 100644 --- a/FS/FS/svc_Common.pm +++ b/FS/FS/svc_Common.pm @@ -1,8 +1,9 @@ package FS::svc_Common; use strict; -use vars qw( @ISA $noexport_hack $DEBUG $me ); -use Carp qw( cluck carp croak ); #specify cluck have to specify them all.. +use vars qw( @ISA $noexport_hack $DEBUG $me + $overlimit_missing_cust_svc_nonfatal_kludge ); +use Carp qw( cluck carp croak confess ); #specify cluck have to specify them all use Scalar::Util qw( blessed ); use FS::Record qw( qsearch qsearchs fields dbh ); use FS::cust_main_Mixin; @@ -18,6 +19,8 @@ use FS::inventory_class; $me = '[FS::svc_Common]'; $DEBUG = 0; +$overlimit_missing_cust_svc_nonfatal_kludge = 0; + =head1 NAME FS::svc_Common - Object method for all svc_ records @@ -798,7 +801,19 @@ Sets or retrieves overlimit date. sub overlimit { my $self = shift; - $self->cust_svc->overlimit(@_); + #$self->cust_svc->overlimit(@_); + my $cust_svc = $self->cust_svc; + unless ( $cust_svc ) { #wtf? + my $error = "$me overlimit: missing cust_svc record for svc_acct svcnum ". + $self->svcnum; + if ( $overlimit_missing_cust_svc_nonfatal_kludge ) { + cluck "$error; continuing anyway as requested"; + return ''; + } else { + confess $error; + } + } + $cust_svc->overlimit(@_); } =item cancel diff --git a/FS/bin/freeside-sqlradius-reset b/FS/bin/freeside-sqlradius-reset index 7d1d34336..5c77747ac 100755 --- a/FS/bin/freeside-sqlradius-reset +++ b/FS/bin/freeside-sqlradius-reset @@ -42,6 +42,10 @@ unless ( $opt_n ) { } } +use FS::svc_Common; +$FS::svc_Common::overlimit_missing_cust_svc_nonfatal_kludge = 1; +$FS::svc_Common::overlimit_missing_cust_svc_nonfatal_kludge = 1; + foreach my $export ( @exports ) { #my @svcparts = map { $_->svcpart } $export->export_svc; -- cgit v1.2.1 From 7bb7306b32e48ae29fc91eb969ba70a465d21c2d Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 4 Aug 2009 23:43:48 +0000 Subject: hopefully ignore errors about deleted accounts and properly finish freeside-sqlradius-reset, RT#5868 --- FS/FS/svc_acct.pm | 14 +++++++++----- FS/bin/freeside-sqlradius-reset | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 6f61eae0e..294e32794 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1496,11 +1496,15 @@ sub radius_check { $check{$pw_attrib} = $password; my $cust_svc = $self->cust_svc; - die "FATAL: no cust_svc record for svc_acct.svcnum ". $self->svcnum. "\n" - unless $cust_svc; - my $cust_pkg = $cust_svc->cust_pkg; - if ( $cust_pkg && $cust_pkg->part_pkg->is_prepaid && $cust_pkg->bill ) { - $check{'Expiration'} = time2str('%B %e %Y %T', $cust_pkg->bill ); #http://lists.cistron.nl/pipermail/freeradius-users/2005-January/040184.html + if ( $cust_svc ) { + my $cust_pkg = $cust_svc->cust_pkg; + if ( $cust_pkg && $cust_pkg->part_pkg->is_prepaid && $cust_pkg->bill ) { + $check{'Expiration'} = time2str('%B %e %Y %T', $cust_pkg->bill ); #http://lists.cistron.nl/pipermail/freeradius-users/2005-January/040184.html + } + } else { + warn "WARNING: no cust_svc record for svc_acct.svcnum ". $self->svcnum. + "; can't set Expiration\n" + unless $cust_svc; } %check; diff --git a/FS/bin/freeside-sqlradius-reset b/FS/bin/freeside-sqlradius-reset index 5c77747ac..a77bad64f 100755 --- a/FS/bin/freeside-sqlradius-reset +++ b/FS/bin/freeside-sqlradius-reset @@ -53,14 +53,25 @@ foreach my $export ( @exports ) { my @svc_x = map { $_->svc_x } - map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) } - grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) } + #map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) } + #grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) } + # $export->export_svc; + map { @{ $_->[1] } } + grep { scalar( @{ $_->[1] } ) } + map { [ $_, [ qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) ] ] } $export->export_svc; + foreach my $svc_x ( @svc_x ) { - $svc_x->check; #set any fixed usergroup so it'll export even if all - #svc_acct records don't have the group yet + #$svc_x->check; #set any fixed usergroup so it'll export even if all + # #svc_acct records don't have the group yet + #more efficient? + my $x = $svc_x->setfixed( $svc_x->_fieldhandlers); + unless ( ref($x) ) { + warn "WARNING: can't set fixed usergroups for svcnum ". $svc_x->svcnum. + "\n"; + } if ($overlimit_groups && $svc_x->overlimit) { $svc_x->usergroup( &{ $svc_x->_fieldhandlers->{'usergroup'} } -- cgit v1.2.1 From f062fac0e5f6c352c1622ed66531f0521980302c Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 5 Aug 2009 02:27:08 +0000 Subject: export negative byte values to chillispot attributes as 0, RT#5815 --- 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 294e32794..ac978640d 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1455,6 +1455,7 @@ sub radius_reply { my $is = $whatis{$what}.'bytes'; if ( $self->$is() =~ /\d/ ) { my $big = new Math::BigInt $self->$is(); + $big = new Math::BigInto '0' if $big->is_neg(); my $att = "Chillispot-Max-\u$what"; $reply{"$att-Octets"} = $big->copy->band(0xffffffff)->bstr; $reply{"$att-Gigawords"} = $big->copy->brsft(32)->bstr; -- cgit v1.2.1 From d6107b6ae3fce55df974ac0a603443adb1d14ba7 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 5 Aug 2009 02:27:35 +0000 Subject: export negative byte values to chillispot attributes as 0, RT#5815 --- FS/FS/svc_acct.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index ac978640d..74bbd1ac4 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1455,7 +1455,7 @@ sub radius_reply { my $is = $whatis{$what}.'bytes'; if ( $self->$is() =~ /\d/ ) { my $big = new Math::BigInt $self->$is(); - $big = new Math::BigInto '0' if $big->is_neg(); + $big = new Math::BigInt '0' if $big->is_neg(); my $att = "Chillispot-Max-\u$what"; $reply{"$att-Octets"} = $big->copy->band(0xffffffff)->bstr; $reply{"$att-Gigawords"} = $big->copy->brsft(32)->bstr; -- cgit v1.2.1 From 94a66b78bcda5605d7ee5eb7c3e692fb2fe5cf2c Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 5 Aug 2009 23:34:28 +0000 Subject: fix cancellation errors with updated flat_introrate, RT#5865 --- FS/FS/part_pkg/agent.pm | 2 +- FS/FS/part_pkg/base_rate.pm | 4 ++-- FS/FS/part_pkg/flat.pm | 10 +++++----- FS/FS/part_pkg/flat_delayed.pm | 2 +- FS/FS/part_pkg/prorate_delayed.pm | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/FS/FS/part_pkg/agent.pm b/FS/FS/part_pkg/agent.pm index 2ebaf5807..d41978cf5 100644 --- a/FS/FS/part_pkg/agent.pm +++ b/FS/FS/part_pkg/agent.pm @@ -119,7 +119,7 @@ sub calc_recur { my $pkg_setup_fee = $part_pkg->setup_cost || $part_pkg->option('setup_fee'); my $pkg_base_recur = - $part_pkg->recur_cost || $part_pkg->base_recur_permonth; + $part_pkg->recur_cost || $part_pkg->base_recur_permonth($cust_pkg); my $pkg_start = $cust_pkg->get('setup'); if ( $pkg_start < $last_bill ) { diff --git a/FS/FS/part_pkg/base_rate.pm b/FS/FS/part_pkg/base_rate.pm index 64636d9ae..440e98518 100644 --- a/FS/FS/part_pkg/base_rate.pm +++ b/FS/FS/part_pkg/base_rate.pm @@ -63,7 +63,7 @@ sub calc_remain { my $time = time; #should be able to pass this in for credit calculation my $next_bill = $cust_pkg->getfield('bill') || 0; my $last_bill = $cust_pkg->last_bill || 0; - return 0 if ! $self->base_recur + return 0 if ! $self->base_recur($cust_pkg) || ! $self->option('unused_credit', 1) || ! $last_bill || ! $next_bill @@ -81,7 +81,7 @@ sub calc_remain { my $freq_sec = $1 * $sec{$2||'m'}; return 0 unless $freq_sec; - sprintf("%.2f", $self->base_recur * ( $next_bill - $time ) / $freq_sec ); + sprintf("%.2f", $self->base_recur($cust_pkg) * ( $next_bill - $time ) / $freq_sec ); } diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index d1863f432..02ac6aeed 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -162,11 +162,11 @@ sub base_recur { } sub base_recur_permonth { - my($self, $cust_pkg) = @_; #$cust_pkg? + my($self, $cust_pkg) = @_; return 0 unless $self->freq =~ /^\d+$/ && $self->freq > 0; - sprintf('%.2f', $self->base_recur / $self->freq ); + sprintf('%.2f', $self->base_recur($cust_pkg) / $self->freq ); } sub calc_remain { @@ -184,7 +184,7 @@ sub calc_remain { #my $last_bill = $cust_pkg->last_bill || 0; my $last_bill = $cust_pkg->get('last_bill') || 0; #->last_bill falls back to setup - return 0 if ! $self->base_recur + return 0 if ! $self->base_recur($cust_pkg) || ! $self->option('unused_credit', 1) || ! $last_bill || ! $next_bill @@ -202,7 +202,7 @@ sub calc_remain { my $freq_sec = $1 * $sec{$2||'m'}; return 0 unless $freq_sec; - sprintf("%.2f", $self->base_recur * ( $next_bill - $time ) / $freq_sec ); + sprintf("%.2f", $self->base_recur($cust_pkg) * ( $next_bill - $time ) / $freq_sec ); } @@ -216,7 +216,7 @@ sub is_prepaid { sub usage_valuehash { my $self = shift; - map { $_, $self->option($_) } + map { $_, $self->option($_) } grep { $self->option($_, 'hush') } qw(seconds upbytes downbytes totalbytes); } diff --git a/FS/FS/part_pkg/flat_delayed.pm b/FS/FS/part_pkg/flat_delayed.pm index 4a2f1baf1..33f9dd80e 100644 --- a/FS/FS/part_pkg/flat_delayed.pm +++ b/FS/FS/part_pkg/flat_delayed.pm @@ -58,7 +58,7 @@ sub calc_remain { return 0 if $last_bill + (86400 * $free_days) == $next_bill && $last_bill == $cust_pkg->setup; - return 0 if ! $self->base_recur + return 0 if ! $self->base_recur($cust_pkg) || ! $self->option('unused_credit', 1) || ! $last_bill || ! $next_bill; diff --git a/FS/FS/part_pkg/prorate_delayed.pm b/FS/FS/part_pkg/prorate_delayed.pm index 1d227984c..0073493ed 100644 --- a/FS/FS/part_pkg/prorate_delayed.pm +++ b/FS/FS/part_pkg/prorate_delayed.pm @@ -56,7 +56,7 @@ sub calc_remain { return 0 if $last_bill + (86400 * $free_days) == $next_bill && $last_bill == $cust_pkg->setup; - return 0 if ! $self->base_recur + return 0 if ! $self->base_recur($cust_pkg) || ! $self->option('unused_credit', 1) || ! $last_bill || ! $next_bill; -- cgit v1.2.1 From 833feb1713594b0146c230f8957d91e14ba0e436 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 6 Aug 2009 00:39:36 +0000 Subject: delete phone_device records when svc_phone is deleted, RT#5226 --- FS/FS/svc_phone.pm | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/FS/FS/svc_phone.pm b/FS/FS/svc_phone.pm index badbb4eb4..11a5a0ee0 100644 --- a/FS/FS/svc_phone.pm +++ b/FS/FS/svc_phone.pm @@ -3,7 +3,7 @@ package FS::svc_phone; use strict; use vars qw( @ISA @pw_set $conf ); use FS::Conf; -use FS::Record qw( qsearch qsearchs ); +use FS::Record qw( qsearch qsearchs dbh ); use FS::Msgcat qw(gettext); use FS::svc_Common; use FS::part_svc; @@ -152,6 +152,39 @@ Delete this record from the database. =cut +sub delete { + my $self = 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'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + foreach my $phone_device ( $self->phone_device ) { + my $error = $phone_device->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + my $error = $self->SUPER::delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + # the delete method can be inherited from FS::Record =item replace OLD_RECORD -- cgit v1.2.1 From b3e081bbd2ba95554687a531bc134c00026a3669 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 6 Aug 2009 00:41:41 +0000 Subject: pass mac addresses as lower-case to netsapiens, RT#5226 --- FS/FS/part_export/netsapiens.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/part_export/netsapiens.pm b/FS/FS/part_export/netsapiens.pm index 9181344fb..a24bc3727 100644 --- a/FS/FS/part_export/netsapiens.pm +++ b/FS/FS/part_export/netsapiens.pm @@ -118,7 +118,7 @@ sub ns_device { #my $countrycode = $svc_phone->countrycode; #my $phonenum = $svc_phone->phonenum; - "/phones_config/". $phone_device->mac_addr; + "/phones_config/". lc($phone_device->mac_addr); } sub ns_create_or_update { -- cgit v1.2.1 From 958afb8d05de67e12df258b57bedcf85028b6253 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 7 Aug 2009 00:39:14 +0000 Subject: don't start recurring billing when a start date hasn't been reached yet either... and since that works, add the start date to new package order, RT#5347 --- FS/FS/cust_main.pm | 7 +++--- httemplate/edit/process/quick-cust_pkg.cgi | 4 +++ httemplate/elements/tr-input-date-field.html | 15 ++++++----- httemplate/misc/order_pkg.html | 37 ++++++++++++++++++++++++++++ httemplate/view/cust_main/packages.html | 1 + 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index becb9054b..8cd03ebc6 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2857,9 +2857,10 @@ sub _make_lines { my $recur = 0; my $unitrecur = 0; my $sdate; - if ( ! $cust_pkg->getfield('susp') and - ( $part_pkg->getfield('freq') ne '0' && - ( $cust_pkg->getfield('bill') || 0 ) <= $time + if ( ! $cust_pkg->get('susp') + and ! $cust_pkg->get('start_date') + and ( $part_pkg->getfield('freq') ne '0' + && ( $cust_pkg->getfield('bill') || 0 ) <= $time ) || ( $part_pkg->plan eq 'voip_cdr' && $part_pkg->option('bill_every_call') diff --git a/httemplate/edit/process/quick-cust_pkg.cgi b/httemplate/edit/process/quick-cust_pkg.cgi index 57c696e7e..7a0f08280 100644 --- a/httemplate/edit/process/quick-cust_pkg.cgi +++ b/httemplate/edit/process/quick-cust_pkg.cgi @@ -49,6 +49,10 @@ my $locationnum = $1; my $cust_pkg = new FS::cust_pkg { 'custnum' => $custnum, 'pkgpart' => $pkgpart, + 'start_date' => ( scalar($cgi->param('start_date')) + ? str2time($cgi->param('start_date')) + : '' + ), 'refnum' => $refnum, 'locationnum' => $locationnum, }; diff --git a/httemplate/elements/tr-input-date-field.html b/httemplate/elements/tr-input-date-field.html index 11581d5bc..428221a5c 100644 --- a/httemplate/elements/tr-input-date-field.html +++ b/httemplate/elements/tr-input-date-field.html @@ -28,12 +28,15 @@ my($name, $value, $label, $format, $usedatetime) = @_; $format = "%m/%d/%Y" unless $format; $label = $name unless $label; -if ($usedatetime) { - my $dt = DateTime->from_epoch(epoch => $value, time_zone => 'floating'); - $value = $dt->strftime($format) - unless $value eq ''; -}else{ - $value = time2str($format, $value); +if ( $value =~ /\S/ ) { + if ( $usedatetime ) { + my $dt = DateTime->from_epoch(epoch => $value, time_zone => 'floating'); + $value = $dt->strftime($format); + } else { + $value = time2str($format, $value); + } +} else { + $value = ''; } diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 9caa57a69..a7571ca58 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -1,5 +1,10 @@ <% include('/elements/header-popup.html', 'Order new package' ) %> + + + + + + % if ( $conf->exists('pkg_referral') ) { <% include('/elements/tr-select-part_referral.html', 'curr_value' => scalar( $cgi->param('refnum') ), #get rid of empty_label first# || $cust_main->refnum, @@ -68,4 +101,8 @@ my $cust_main = qsearchs({ my $pkgpart = scalar($cgi->param('pkgpart')); +my $format = "%m/%d/%Y %T %z (%Z)"; #false laziness w/REAL_cust_pkg.cgi? +my $start_date = $cust_main->next_bill_date; +$start_date = $start_date ? time2str($format, $start_date) : ''; + diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html index 8fbefae50..16adc8c5f 100755 --- a/httemplate/view/cust_main/packages.html +++ b/httemplate/view/cust_main/packages.html @@ -9,6 +9,7 @@ 'cust_main' => $cust_main, 'closetext' => 'Close', 'width' => 763, + 'height' => 350, ) %> % } -- cgit v1.2.1 From c183de0b7e942672cafdc1c14a203e389ffd2c43 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 7 Aug 2009 23:08:03 +0000 Subject: add ability to edit signup dates (turn on cust_main-edit_signupdate config), RT#4644 --- FS/FS/Conf.pm | 7 +++++ httemplate/edit/cust_main.cgi | 3 +- httemplate/edit/cust_main/top_misc.html | 10 ++++++ httemplate/edit/process/cust_main.cgi | 47 ++++++++++++++++++++-------- httemplate/elements/tr-input-date-field.html | 14 +++++++-- 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index c335c0140..66f74578d 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -3016,6 +3016,13 @@ worry that config_items is freeside-specific and icky. 'type' => 'checkbox', }, + { + 'key' => 'cust_main-edit_signupdate', + 'section' => 'UI', + 'descritpion' => 'Enable manual editing of the signup date.', + 'type' => 'checkbox', + }, + { key => "apacheroot", section => "deprecated", description => "DEPRECATED", type => "text" }, { key => "apachemachine", section => "deprecated", description => "DEPRECATED", type => "text" }, { key => "apachemachines", section => "deprecated", description => "DEPRECATED", type => "text" }, diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 8b1d2b59c..15c9f45b2 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -56,7 +56,7 @@ % } % } -

+
Billing address <% include('cust_main/contact.html', @@ -182,6 +182,7 @@ function samechanged(what) { +%# cust_main/bottomfixup.js % foreach my $hidden ( % 'payauto', % 'payinfo', 'payinfo1', 'payinfo2', 'paytype', diff --git a/httemplate/edit/cust_main/top_misc.html b/httemplate/edit/cust_main/top_misc.html index 5aaa0b0cc..041050664 100644 --- a/httemplate/edit/cust_main/top_misc.html +++ b/httemplate/edit/cust_main/top_misc.html @@ -71,6 +71,16 @@ % } +%# signup date +% if ( $conf->exists('cust_main-edit_signupdate') ) { + <% include('/elements/tr-input-date-field.html', { + 'name' => 'signupdate', + 'value' => $cust_main->signupdate, + 'label' => 'Signup date', + 'format' => $conf->config('date_format') || "%m/%d/%Y", + }) + %> +% } diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 1709752fb..f72ca0a81 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -73,20 +73,41 @@ if ( defined($cgi->param('same')) && $cgi->param('same') eq "Y" ) { ); } -if ( $cgi->param('birthdate') && $cgi->param('birthdate') =~ /^([ 0-9\-\/]{0,10})$/) { - my $format = $conf->config('date_format') || "%m/%d/%Y"; - my $parser = DateTime::Format::Strptime->new(pattern => $format, - time_zone => 'floating', - ); - my $dt = $parser->parse_datetime($1); - if ($dt) { - $new->setfield('birthdate', $dt->epoch); - $cgi->param('birthdate', $dt->epoch); - } else { -# $error ||= $cgi->param('birthdate') . " is an invalid birthdate:" . $parser->errmsg; - $error ||= "Invalid birthdate: " . $cgi->param('birthdate') . "."; - $cgi->param('birthdate', ''); +my %usedatetime = ( 'birthdate' => 1 ); + +foreach my $dfield (qw( birthdate signupdate )) { + + if ( $cgi->param($dfield) && $cgi->param($dfield) =~ /^([ 0-9\-\/]{0,10})$/) { + + my $value = $1; + my $parsed = ''; + + if ( exists $usedatetime{$dfield} && $usedatetime{$dfield} ) { + + my $format = $conf->config('date_format') || "%m/%d/%Y"; + my $parser = DateTime::Format::Strptime->new( pattern => $format, + time_zone => 'floating', + ); + my $dt = $parser->parse_datetime($value); + if ( $dt ) { + $parsed = $dt->epoch; + } else { + # $error ||= $cgi->param('birthdate') . " is an invalid birthdate:" . $parser->errmsg; + $error ||= "Invalid $dfield: $value"; + } + + } else { + + $parsed = str2time($value) + or $error ||= "Invalid $dfield: $value"; + + } + + $new->setfield( $dfield, $parsed ); + $cgi->param( $dfield, $parsed ); + } + } $new->setfield('paid', $cgi->param('paid') ) diff --git a/httemplate/elements/tr-input-date-field.html b/httemplate/elements/tr-input-date-field.html index 428221a5c..2a731e1e8 100644 --- a/httemplate/elements/tr-input-date-field.html +++ b/httemplate/elements/tr-input-date-field.html @@ -23,7 +23,17 @@ <%init> -my($name, $value, $label, $format, $usedatetime) = @_; +my($name, $value, $label, $format, $usedatetime); +if ( ref($_[0]) ) { + my $opt = shift; + $name = $opt->{'name'}; + $value = $opt->{'value'}; + $label = $opt->{'label'}; + $format = $opt->{'format'}; + $usedatetime = $opt->{'usedatetime'}; +} else { + ($name, $value, $label, $format, $usedatetime) = @_; +} $format = "%m/%d/%Y" unless $format; $label = $name unless $label; @@ -32,7 +42,7 @@ if ( $value =~ /\S/ ) { if ( $usedatetime ) { my $dt = DateTime->from_epoch(epoch => $value, time_zone => 'floating'); $value = $dt->strftime($format); - } else { + } elsif ( $value =~ /^\d+$/ ) { $value = time2str($format, $value); } } else { -- cgit v1.2.1 From 283ea2b5137ae3ec36882b492e6de024b0ce6027 Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 9 Aug 2009 09:05:38 +0000 Subject: Add cust_attachment stuff --- FS/FS/AccessRight.pm | 3 + FS/FS/Conf.pm | 14 +++ FS/FS/Mason.pm | 1 + FS/FS/Record.pm | 8 +- FS/FS/Schema.pm | 16 +++ FS/FS/cust_attachment.pm | 170 +++++++++++++++++++++++++++ httemplate/edit/cust_main_attach.cgi | 58 +++++++++ httemplate/edit/process/cust_main_attach.cgi | 88 ++++++++++++++ httemplate/view/attachment.html | 16 +++ httemplate/view/cust_main.cgi | 28 +++-- httemplate/view/cust_main/attachments.html | 133 +++++++++++++++++++++ 11 files changed, 523 insertions(+), 12 deletions(-) create mode 100644 FS/FS/cust_attachment.pm create mode 100755 httemplate/edit/cust_main_attach.cgi create mode 100644 httemplate/edit/process/cust_main_attach.cgi create mode 100644 httemplate/view/attachment.html create mode 100755 httemplate/view/cust_main/attachments.html diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index 29cecd5f2..d19212520 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -100,6 +100,9 @@ tie my %rights, 'Tie::IxHash', { rightname=>'Delete customer', desc=>"Enable customer deletions. Be very careful! Deleting a customer will remove all traces that this customer ever existed! It should probably only be used when auditing a legacy database. Normally, you cancel all of a customer's packages if they cancel service." }, #aka. deletecustomers 'Add customer note', #NEW 'Edit customer note', #NEW + 'Download attachment', #NEW + 'Add attachment', #NEW + 'Edit attachment', #NEW 'Bill customer now', #NEW 'Bulk send customer notices', #NEW ], diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 66f74578d..1da55837c 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -735,6 +735,20 @@ worry that config_items is freeside-specific and icky. 'type' => 'text', }, + { + 'key' => 'disable_cust_attachment', + 'section' => '', + 'description' => 'Disable customer file attachments', + 'type' => 'checkbox', + }, + + { + 'key' => 'max_attachment_size', + 'section' => '', + 'description' => 'Maximum size for customer file attachments (leave blank for unlimited)', + 'type' => 'text', + }, + { 'key' => 'disable_customer_referrals', 'section' => 'UI', diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index ed99bf694..d73d3810a 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -186,6 +186,7 @@ Initializes the Mason environment, loads all Freeside and RT libraries, etc. use FS::part_pkg_taxrate; use FS::tax_rate; use FS::part_pkg_report_option; + use FS::cust_attachment; use FS::h_cust_pkg; use FS::h_svc_acct; use FS::h_svc_broadband; diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 9e1c0e890..11afd9ff6 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -55,14 +55,13 @@ FS::UID->install_callback( sub { $conf_encryption = $conf->exists('encryption'); $File::CounterFile::DEFAULT_DIR = $conf->base_dir . "/counters.". datasrc; if ( driver_name eq 'Pg' ) { - eval "use DBD::Pg qw(:pg_types);"; + eval "use DBD::Pg ':pg_types'"; die $@ if $@; } else { eval "sub PG_BYTEA { die 'guru meditation #9: calling PG_BYTEA when not running Pg?'; }"; } } ); - =head1 NAME FS::Record - Database record objects @@ -2718,7 +2717,10 @@ sub _quote { ) { no strict 'subs'; - dbh->quote($value, PG_BYTEA); +# dbh->quote($value, { pg_type => PG_BYTEA() }); # doesn't work right + # Pg binary string quoting: convert each character to 3-digit octal prefixed with \\, + # single-quote the whole mess, and put an "E" in front. + return ("E'" . join('', map { sprintf('\\\\%03o', ord($_)) } split(//, $value) ) . "'"); } else { dbh->quote($value); } diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 80aed8297..0ede00031 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -372,6 +372,22 @@ sub tables_hashref { 'index' => [ ['typenum'] ], }, + 'cust_attachment' => { + 'columns' => [ + 'attachnum', 'serial', '', '', '', '', + 'custnum', 'int', '', '', '', '', + '_date', @date_type, '', '', + 'otaker', 'varchar', '', 32, '', '', + 'filename', 'varchar', '', 32, '', '', + 'mime_type', 'varchar', '', 32, '', '', + 'body', 'blob', 'NULL', '', '', '', + 'disabled', @date_type, '', '', + ], + 'primary_key' => 'attachnum', + 'unique' => [], + 'index' => [ ['custnum'] ], + }, + 'cust_bill' => { 'columns' => [ 'invnum', 'serial', '', '', '', '', diff --git a/FS/FS/cust_attachment.pm b/FS/FS/cust_attachment.pm new file mode 100644 index 000000000..9527381f4 --- /dev/null +++ b/FS/FS/cust_attachment.pm @@ -0,0 +1,170 @@ +package FS::cust_attachment; + +use strict; +use base qw( FS::Record ); +use FS::Record qw( qsearch qsearchs ); +use FS::Conf; + +=head1 NAME + +FS::cust_attachment - Object methods for cust_attachment records + +=head1 SYNOPSIS + + use FS::cust_attachment; + + $record = new FS::cust_attachment \%hash; + $record = new FS::cust_attachment { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_attachment object represents a file attached to a L +object. FS::cust_attachment inherits from FS::Record. The following fields +are currently supported: + +=over 4 + +=item attachnum + +Primary key (assigned automatically). + +=item custnum + +Customer number (see L). + +=item _date + +The date the record was last updated. + +=item otaker + +Order taker (assigned automatically; see L). + +=item filename + +The file's name. + +=item mime_type + +The Content-Type of the file. + +=item body + +The contents of the file. + +=item disabled + +If the attachment was disabled, this contains the date it was disabled. + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new attachment object. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'cust_attachment'; } + +sub nohistory_fields { 'body'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +=item delete + +Delete this record from the database. + +=cut + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +# the replace method can be inherited from FS::Record + +=item check + +Checks all fields to make sure this is a valid example. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $conf = new FS::Conf; + my $error; + if($conf->config('disable_cust_attachment') ) { + $error = 'Attachments disabled (see configuration)'; + } + + $error = + $self->ut_numbern('attachnum') + || $self->ut_number('custnum') + || $self->ut_numbern('_date') + || $self->ut_text('otaker') + || $self->ut_text('filename') + || $self->ut_text('mime_type') + || $self->ut_numbern('disabled') + || $self->ut_anything('body') + ; + if($conf->config('max_attachment_size') + and $self->size > $conf->config('max_attachment_size') ) { + $error = 'Attachment too large' + } + return $error if $error; + + $self->SUPER::check; +} + +=item size + +Returns the size of the attachment in bytes. + +=cut + +sub size { + my $self = shift; + return length($self->body); +} + +=back + +=head1 BUGS + +Doesn't work on non-Postgres systems. + +=head1 SEE ALSO + +L, schema.html from the base documentation. + +=cut + +1; + diff --git a/httemplate/edit/cust_main_attach.cgi b/httemplate/edit/cust_main_attach.cgi new file mode 100755 index 000000000..7c9e407d9 --- /dev/null +++ b/httemplate/edit/cust_main_attach.cgi @@ -0,0 +1,58 @@ +<% include('/elements/header-popup.html', "$action File Attachment") %> + +<% include('/elements/error.html') %> + +
+ + + +

+ +% if(defined $attach) { +Filename
+MIME type +Size: <% $attach->size %>
+ +% } +% else { # !defined $attach + +Filename
+ +% } + +
+"> + +% if(defined $attach) { +
+ +% } + +
+ + + +<%init> + +my $attachnum = ''; +my $attach; +if ( $cgi->param('error') ) { + #$comment = $cgi->param('comment'); +} elsif ( $cgi->param('attachnum') =~ /^(\d+)$/ ) { + $attachnum = $1; + die "illegal query ". $cgi->keywords unless $attachnum; + $attach = qsearchs('cust_attachment', { 'attachnum' => $attachnum }); + die "no such attachment: ". $attachnum unless $attach; +} + +$cgi->param('custnum') =~ /^(\d+)$/ or die "illegal custnum"; +my $custnum = $1; + +my $action = $attachnum ? 'Edit' : 'Add'; + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right("$action customer note"); + + + diff --git a/httemplate/edit/process/cust_main_attach.cgi b/httemplate/edit/process/cust_main_attach.cgi new file mode 100644 index 000000000..51eead076 --- /dev/null +++ b/httemplate/edit/process/cust_main_attach.cgi @@ -0,0 +1,88 @@ +%if ($error) { +% $cgi->param('error', $error); +<% $cgi->redirect(popurl(2). 'cust_main_attach.cgi?'. $cgi->query_string ) %> +%} else { +% my $act = 'added'; +% $act = 'updated' if ($attachnum); +% $act = 'undeleted' if($attachnum and $undelete); +% $act = 'deleted' if($attachnum and $delete); +<% header('Attachment ' . $act ) %> + + +% } +<%init> + +my $error; +$cgi->param('custnum') =~ /^(\d+)$/ + or die "Illegal custnum: ". $cgi->param('custnum'); +my $custnum = $1; + +$cgi->param('attachnum') =~ /^(\d*)$/ + or die "Illegal attachnum: ". $cgi->param('attachnum'); +my $attachnum = $1; + +my $otaker = $FS::CurrentUser::CurrentUser->name; +$otaker = $FS::CurrentUser::CurrentUser->username + if ($otaker eq "User, Legacy"); + +my $delete = $cgi->param('delete'); +my $undelete = $cgi->param('undelete'); + +my $new = new FS::cust_attachment ( { + attachnum => $attachnum, + custnum => $custnum, + _date => time, + otaker => $otaker, + disabled => '', +}); +my $old; + +if($attachnum) { + $old = qsearchs('cust_attachment', { attachnum => $attachnum }); + if(!$old) { + $error = "Attachnum '$attachnum' not found"; + } + else { + map { $new->$_($old->$_) } + ('_date', 'otaker', 'body', 'disabled'); + $new->filename($cgi->param('filename') || $old->filename); + $new->mime_type($cgi->param('mime_type') || $old->mime_type); + if($delete and not $old->disabled) { + $new->disabled(time); + } + if($undelete and $old->disabled) { + $new->disabled(''); + } + } +} +else { # This is a new attachment, so require a file. + + my $filename = $cgi->param('file'); + if($filename) { + $new->filename($filename); + $new->mime_type($cgi->uploadInfo($filename)->{'Content-Type'}); + + local $/; + my $fh = $cgi->upload('file'); + $new->body(<$fh>); + } + else { + $error = 'No file uploaded'; + } +} +my $user = $FS::CurrentUser::CurrentUser; + +$error = 'access denied' unless $user->access_right(($old ? 'Edit' : 'Add') . ' attachment'); + +if(!$error) { + if($old) { + $error = $new->replace($old); + } + else { + $error = $new->insert; + } +} + + diff --git a/httemplate/view/attachment.html b/httemplate/view/attachment.html new file mode 100644 index 000000000..c85b1375f --- /dev/null +++ b/httemplate/view/attachment.html @@ -0,0 +1,16 @@ +<%init> +my ($query) = $cgi->keywords; +$query =~ /^(\d+)$/; +my $attachnum = $1 or die 'Invalid attachment number'; +$FS::CurrentUser::CurrentUser->access_right('Download attachment') or die 'access denied'; + +my $attach = qsearchs('cust_attachment', { attachnum => $attachnum }) or die 'Attachment not found: $attachnum'; + +$m->clear_buffer; +$r->content_type($attach->mime_type || 'text/plain'); +$r->headers_out->add('Content-Disposition' => 'attachment;filename=' . $attach->filename); + +binmode STDOUT; +print STDOUT $attach->body; + + diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 78bcb1fc1..da1a56a96 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -113,7 +113,6 @@ Comments % if ( ! $conf->exists('cust_main-disable_notes') || $notecount) { % unless ( $view eq 'notes' && $cust_main->comments !~ /[^\s\n\r]/ ) { -
Notes
% } @@ -138,6 +137,22 @@ Comments <% include('cust_main/notes.html', 'custnum' => $cust_main->custnum ) %> % } +
+ +% if(! $conf->config('disable_cust_attachment') +% and $curuser->access_right('Add attachment')) { +<% include( '/elements/popup_link-cust_main.html', + 'label' => 'Attach file', + 'action' => $p.'edit/cust_main_attach.cgi', + 'actionlabel' => 'Upload file', + 'cust_main' => $cust_main, + 'width' => 616, + 'height' => 408, + ) +%> +% } +<% include('cust_main/attachments.html', 'custnum' => $cust_main->custnum ) %> +
% } @@ -181,10 +196,6 @@ Comments % } -% if ( $view eq 'change_history' ) { # || $view eq 'jumbo' - <% include('cust_main/change_history.html', $cust_main ) %> -% } - <% include('/elements/footer.html') %> <%init> @@ -218,12 +229,11 @@ tie my %views, 'Tie::IxHash', 'Notes' => 'notes', #notes and files? ; $views{'Tickets'} = 'tickets' - if $conf->config('ticket_system'); + if $conf->config('ticket_system'); $views{'Packages'} = 'packages'; $views{'Payment History'} = 'payment_history' - unless $conf->config('payby-default' eq 'HIDE'); -$views{'Change History'} = 'change_history' - if $curuser->access_right('View customer history'); + unless $conf->config('payby-default' eq 'HIDE'); +#$views{'Change History'} = ''; $views{'Jumbo'} = 'jumbo'; my %viewname = reverse %views; diff --git a/httemplate/view/cust_main/attachments.html b/httemplate/view/cust_main/attachments.html new file mode 100755 index 000000000..e25814ff5 --- /dev/null +++ b/httemplate/view/cust_main/attachments.html @@ -0,0 +1,133 @@ +% if ( scalar(@attachments) ) { + + <% include('/elements/init_overlib.html') %> + + <% include("/elements/table-grid.html") %> + + + Date +% if ( $conf->exists('cust_main_note-display_times') ) { + Time +% } + Person + Filename + Type + Size + + + +% my $bgcolor1 = '#eeeeee'; +% my $bgcolor2 = '#ffffff'; +% my $bgcolor = ''; +% +% foreach my $attach ((grep { $_->disabled } @attachments), +% (grep { ! $_->disabled } @attachments)) { +% +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; +% } +% +% my $pop = popurl(3); +% my $attachnum = $attach->attachnum; +% my $edit = ''; +% my $download = ''; +% if($attach->disabled) { +% my $onclick = include('/elements/popup_link_onclick.html', +% 'action' => popurl(2). +% 'edit/process/cust_main_attach.cgi'. +% "?custnum=$custnum;". +% "attachnum=$attachnum;". +% "undelete=1", +% 'actionlabel' => 'Undelete attachment', +% 'width' => 616, +% 'height' => 408, +% 'frame' => 'top', +% ); +% my $clickjs = qq!onclick="$onclick"!; +% if($curuser->access_right('Edit attachment')) { +% $edit = qq! (undelete)!; +% } +% } +% else { +% my $onclick = include( '/elements/popup_link_onclick.html', +% 'action' => popurl(2). +% 'edit/cust_main_attach.cgi'. +% "?custnum=$custnum". +% ";attachnum=$attachnum", +% 'actionlabel' => 'Edit customer note', +% 'width' => 616, +% 'height' => 408, +% 'frame' => 'top', +% ); +% my $clickjs = qq!onclick="$onclick"!; +% +% if ($curuser->access_right('Edit attachment') ) { +% $edit = qq! (edit)!; +% } +% if ($curuser->access_right('Download attachment') ) { +% $download = qq! (download)!; +% } +% } + + + <% note_datestr($attach,$conf,$bgcolor) %> + +  <% $attach->otaker%> + + +  <% $attach->filename %> + + +  <% $attach->mime_type %> + + +  <% size_units( $attach->size ) %> + + +  <% $edit %> +  <% $download %> + + <% $attach->disabled ? '' : '' %> + + +% } #end display notes + + + +% } +<%init> + +my $conf = new FS::Conf; +my $curuser = $FS::CurrentUser::CurrentUser; + +my(%opt) = @_; + +my $custnum = $opt{'custnum'}; + +my $cust_main = qsearchs('cust_main', {'custnum' => $custnum} ); +die "Customer not found!" unless $cust_main; + +my (@attachments) = qsearch('cust_attachment', {'custnum' => $custnum}); + +#subroutines + +sub note_datestr { + my($note, $conf, $bgcolor) = @_ or return ''; + my $td = qq{}; + my $format = "$td%b %o, %Y"; + $format .= "$td%l:%M%P" + if $conf->exists('cust_main_note-display_times'); + ( my $strip = time2str($format, $note->_date) ) =~ s/ (\d)/$1/g; + $strip; +} + +sub size_units { + my $bytes = shift; + return $bytes if $bytes < 1024; + return int($bytes / 1024)."K" if $bytes < 1048576; + return int($bytes / 1048576)."M"; +} + + -- cgit v1.2.1 From d4c01ecffef02ef160d8c367270324e3d6a1c75d Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 9 Aug 2009 22:47:57 +0000 Subject: don't bomb when the line item has no start date --- FS/FS/cust_bill_pkg.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index abf021845..bb30f03cd 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -299,6 +299,7 @@ Returns the previous cust_bill_pkg for this package, if any. sub previous_cust_bill_pkg { my $self = shift; + return unless $self->sdate; qsearchs({ 'table' => 'cust_bill_pkg', 'hashref' => { 'pkgnum' => $self->pkgnum, -- cgit v1.2.1 From 81b342e3f83b433979a25c75cf287ad394ad8513 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 9 Aug 2009 23:45:06 +0000 Subject: fix per agent spools --- FS/FS/part_event/Action/cust_bill_spool_csv.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/FS/FS/part_event/Action/cust_bill_spool_csv.pm b/FS/FS/part_event/Action/cust_bill_spool_csv.pm index f20ee46c9..11bb7b1a8 100644 --- a/FS/FS/part_event/Action/cust_bill_spool_csv.pm +++ b/FS/FS/part_event/Action/cust_bill_spool_csv.pm @@ -35,6 +35,7 @@ sub option_fields { }, 'spoolagent_spools' => { label => 'Individual per-agent spools', type => 'checkbox', + value => 'Y', }, ); } -- cgit v1.2.1 From 39000f1ad925a76a4a334271b8e9e5da6a5dcb89 Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 9 Aug 2009 23:53:39 +0000 Subject: whoops: theory should match practice --- FS/FS/part_event/Action/cust_bill_spool_csv.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/part_event/Action/cust_bill_spool_csv.pm b/FS/FS/part_event/Action/cust_bill_spool_csv.pm index 11bb7b1a8..43d230033 100644 --- a/FS/FS/part_event/Action/cust_bill_spool_csv.pm +++ b/FS/FS/part_event/Action/cust_bill_spool_csv.pm @@ -35,7 +35,7 @@ sub option_fields { }, 'spoolagent_spools' => { label => 'Individual per-agent spools', type => 'checkbox', - value => 'Y', + value => '1', }, ); } -- cgit v1.2.1 From 99100d7e0d0b22a1844dde88acd529e79d096463 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 10 Aug 2009 11:50:04 +0000 Subject: when using pkg-balances, limit self-service access when a customer with multiple packages logs on, RT#4189 --- FS/FS/ClientAPI/MyAccount.pm | 149 +++++++++++++++------ fs_selfservice/FS-SelfService/SelfService.pm | 1 + fs_selfservice/FS-SelfService/cgi/login.html | 2 +- fs_selfservice/FS-SelfService/cgi/logout.html | 2 +- .../cgi/make_thirdparty_payment.html | 13 +- fs_selfservice/FS-SelfService/cgi/myaccount.html | 12 +- .../FS-SelfService/cgi/myaccount_menu.html | 65 +++++---- fs_selfservice/FS-SelfService/cgi/selfservice.cgi | 10 +- 8 files changed, 174 insertions(+), 80 deletions(-) diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 9d031be33..b6934f8bd 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -60,17 +60,20 @@ sub skin_info { my $conf = new FS::Conf; - my %skin = ( - 'head' => join("\n", $conf->config('selfservice-head') ), - 'body_header' => join("\n", $conf->config('selfservice-body_header') ), - 'body_footer' => join("\n", $conf->config('selfservice-body_footer') ), - 'body_bgcolor' => scalar( $conf->config('selfservice-body_bgcolor') ), - 'box_bgcolor' => scalar( $conf->config('selfservice-box_bgcolor') ), + use vars qw($skin_info); #cache for performance. + #agentnum eventually...? but if they're not logged in yet.. ? + + $skin_info ||= { + 'head' => join("\n", $conf->config('selfservice-head') ), + 'body_header' => join("\n", $conf->config('selfservice-body_header') ), + 'body_footer' => join("\n", $conf->config('selfservice-body_footer') ), + 'body_bgcolor' => scalar( $conf->config('selfservice-body_bgcolor') ), + 'box_bgcolor' => scalar( $conf->config('selfservice-box_bgcolor') ), 'company_name' => scalar($conf->config('company_name')), - ); + }; - \%skin; + $skin_info; } @@ -80,6 +83,7 @@ sub login_info { my $conf = new FS::Conf; my %info = ( + %{ skin_info() }, 'phone_login' => $conf->exists('selfservice_server-phone_login'), 'single_domain'=> scalar($conf->config('selfservice_server-single_domain')), ); @@ -122,16 +126,6 @@ sub login { ); return { error => 'User not found.' } unless $svc_acct; - #my $pkg_svc = $svc_acct->cust_svc->pkg_svc; - #return { error => 'Only primary user may log in.' } - # if $conf->exists('selfservice_server-primary_only') - # && ( ! $pkg_svc || $pkg_svc->primary_svc ne 'Y' ); - my $cust_svc = $svc_acct->cust_svc; - my $part_pkg = $cust_svc->cust_pkg->part_pkg; - return { error => 'Only primary user may log in.' } - if $conf->exists('selfservice_server-primary_only') - && $cust_svc->svcpart != $part_pkg->svcpart('svc_acct'); - return { error => 'Incorrect password.' } unless $svc_acct->check_password($p->{'password'}); @@ -143,14 +137,28 @@ sub login { 'svcnum' => $svc_x->svcnum, }; - my $cust_pkg = $svc_x->cust_svc->cust_pkg; + my $cust_svc = $svc_x->cust_svc; + my $cust_pkg = $cust_svc->cust_pkg; if ( $cust_pkg ) { my $cust_main = $cust_pkg->cust_main; $session->{'custnum'} = $cust_main->custnum; - $session->{'pkgnum'} = $cust_pkg->pkgnum - if $conf->exists('pkg-balances'); + if ( $conf->exists('pkg-balances') ) { + my @cust_pkg = grep { $_->part_pkg->freq !~ /^(0|$)/ } + $cust_main->ncancelled_pkgs; + $session->{'pkgnum'} = $cust_pkg->pkgnum + if scalar(@cust_pkg) > 1; + } } + #my $pkg_svc = $svc_acct->cust_svc->pkg_svc; + #return { error => 'Only primary user may log in.' } + # if $conf->exists('selfservice_server-primary_only') + # && ( ! $pkg_svc || $pkg_svc->primary_svc ne 'Y' ); + my $part_pkg = $cust_pkg->part_pkg; + return { error => 'Only primary user may log in.' } + if $conf->exists('selfservice_server-primary_only') + && $cust_svc->svcpart != $part_pkg->svcpart([qw( svc_acct svc_phone )]); + my $session_id; do { $session_id = md5_hex(md5_hex(time(). {}. rand(). $$)) @@ -168,12 +176,57 @@ sub logout { my $p = shift; if ( $p->{'session_id'} ) { _cache->remove($p->{'session_id'}); - return { 'error' => '' }; + return { %{ skin_info() }, 'error' => '' }; } else { - return { 'error' => "Can't resume session" }; #better error message + return { %{ skin_info() }, 'error' => "Can't resume session" }; #better error message } } +sub access_info { + my $p = shift; + + my $conf = new FS::Conf; + + my $info = skin_info($p); + + use vars qw( $cust_paybys ); #cache for performance + unless ( $cust_paybys ) { + + my %cust_paybys = map { $_ => 1 } + map { FS::payby->payby2payment($_) } + $conf->config('signup_server-payby'); + + $cust_paybys = [ keys %cust_paybys ]; + + } + $info->{'cust_paybys'} = $cust_paybys; + + my($context, $session, $custnum) = _custoragent_session_custnum($p); + return { 'error' => $session } if $context eq 'error'; + + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or return { 'error' => "unknown custnum $custnum" }; + + $info->{hide_payment_fields} = + [ + map { FS::payby->realtime($_) && + $cust_main + ->agent + ->payment_gateway( 'method' => FS::payby->payby2bop($_) ) + ->gateway_namespace + eq 'Business::OnlineThirdPartyPayment' + } + @{ $info->{cust_paybys} } + ]; + + return { %$info, + 'custnum' => $custnum, + 'pkgnum' => $session->{'pkgnum'}, + 'svcnum' => $session->{'svcnum'}, + 'nonprimary' => $session->{'nonprimary'}, + }; +} + sub customer_info { my $p = shift; @@ -196,21 +249,32 @@ sub customer_info { my $cust_main = qsearchs('cust_main', $search ) or return { 'error' => "unknown custnum $custnum" }; - $return{balance} = $cust_main->balance; + if ( $session->{'pkgnum'} ) { + $return{balance} = $cust_main->balance_pkgnum( $session->{'pkgnum'} ); + } else { + $return{balance} = $cust_main->balance; + } $return{tickets} = [ ($cust_main->tickets) ]; - my @open = map { - { - invnum => $_->invnum, - date => time2str("%b %o, %Y", $_->_date), - owed => $_->owed, - }; - } $cust_main->open_cust_bill; - $return{open_invoices} = \@open; + unless ( $session->{'pkgnum'} ) { + my @open = map { + { + invnum => $_->invnum, + date => time2str("%b %o, %Y", $_->_date), + owed => $_->owed, + }; + } $cust_main->open_cust_bill; + $return{open_invoices} = \@open; + } $return{small_custview} = - small_custview( $cust_main, $conf->config('countrydefault') ); + small_custview( $cust_main, + scalar($conf->config('countrydefault')), + ( $session->{'pkgnum'} ? 1 : 0 ), #nobalance + ); + + warn $return{small_custview}; $return{name} = $cust_main->first. ' '. $cust_main->get('last'); @@ -359,6 +423,12 @@ sub payment_info { 'country' => $conf->config('countrydefault') || 'US' } ); + my %cust_paybys = map { $_ => 1 } + map { FS::payby->payby2payment($_) } + $conf->config('signup_server-payby'); + + my @cust_paybys = keys %cust_paybys; + $payment_info = { #list all counties/states/countries @@ -374,9 +444,7 @@ sub payment_info { 'paytypes' => [ @FS::cust_main::paytypes ], 'paybys' => [ $conf->config('signup_server-payby') ], - 'cust_paybys' => [ map { FS::payby->payby2payment($_) } - $conf->config('signup_server-payby') - ], + 'cust_paybys' => \@cust_paybys, 'stateid_label' => FS::Msgcat::_gettext('stateid'), 'stateid_state_label' => FS::Msgcat::_gettext('stateid_state'), @@ -411,7 +479,7 @@ sub payment_info { @{ $return{cust_paybys} } ]; - $return{balance} = $cust_main->balance; + $return{balance} = $cust_main->balance; #XXX pkg-balances? $return{payname} = $cust_main->payname || ( $cust_main->first. ' '. $cust_main->get('last') ); @@ -589,7 +657,11 @@ sub realtime_collect { ); return { 'error' => $error } unless ref( $error ); - return { 'error' => '', amount => $cust_main->balance, %$error }; + my $amount = $session->{'pkgnum'} + ? $cust_main->balance_pkgnum( $session->{'pkgnum'} ) + : $cust_main->balance; + + return { 'error' => '', amount => $amount, %$error }; } sub process_payment_order_pkg { @@ -802,6 +874,7 @@ sub list_svcs { foreach my $cust_pkg ( $p->{'ncancelled'} ? $cust_main->ncancelled_pkgs : $cust_main->unsuspended_pkgs ) { + next if $session->{'pkgnum'} && $cust_pkg->pkgnum != $session->{'pkgnum'}; push @cust_svc, @{[ $cust_pkg->cust_svc ]}; #@{[ ]} to force array context } if ( $p->{'svcdb'} ) { diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index d275fa86d..743057d88 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -61,6 +61,7 @@ $socket .= '.'.$tag if defined $tag && length($tag); 'myaccount_passwd' => 'MyAccount/myaccount_passwd', 'signup_info' => 'Signup/signup_info', 'skin_info' => 'MyAccount/skin_info', + 'access_info' => 'MyAccount/access_info', 'domain_select_hash' => 'Signup/domain_select_hash', # expose? 'new_customer' => 'Signup/new_customer', 'capture_payment' => 'Signup/capture_payment', diff --git a/fs_selfservice/FS-SelfService/cgi/login.html b/fs_selfservice/FS-SelfService/cgi/login.html index 760f579bb..eef412da3 100644 --- a/fs_selfservice/FS-SelfService/cgi/login.html +++ b/fs_selfservice/FS-SelfService/cgi/login.html @@ -3,7 +3,7 @@ Login <%= $head %> - + <%= $body_header %> Login

diff --git a/fs_selfservice/FS-SelfService/cgi/logout.html b/fs_selfservice/FS-SelfService/cgi/logout.html index e2de648ce..5e22ad80c 100644 --- a/fs_selfservice/FS-SelfService/cgi/logout.html +++ b/fs_selfservice/FS-SelfService/cgi/logout.html @@ -3,7 +3,7 @@ MyAccount <%= $head %> - + <%= $body_header %> MyAccount

diff --git a/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html b/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html index 042b8b37c..b2900b1e9 100755 --- a/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html +++ b/fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html @@ -1,5 +1,6 @@ -My Account -MyAccount

+<%= $url = "$selfurl?session=$session_id;action="; ''; %> +<%= include('header') %> + -<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - + Pay now

<%= if ( $error ) { @@ -34,5 +33,5 @@ EOF $OUT .= qq!!; } %> - - + +<%= include('footer') %> diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html index bcfcf9540..d6527fe76 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html @@ -4,11 +4,17 @@ Hello <%= $name %>!

<%= $small_custview %>
+<%= if ( $pkgnum ) { + $OUT .= qq!Balance: \$$balance

!; + } + ''; +%> + <%= if ( $balance > 0 ) { - if (scalar(grep $_, @hide_payment_field)) { - $OUT .= qq! Make a payment

!; - } else { + if (scalar(grep $_, @hide_payment_fields)) { $OUT .= qq! Make a payment

!; + } else { + $OUT .= qq! Make a payment

!; } } %> <%= diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html index 5cf4fe2d9..617ae3ebe 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html @@ -7,15 +7,18 @@ <%= my @menu = ( -{ title=>' ' }, -{ title=>'Overview', url=>'myaccount', size=>'+1', }, -{ title=>' ' }, - -{ title=>'Purchase', size=>'+1', }, - { title=>'Purchase additional package', - url=>'customer_order_pkg', 'indent'=>2 }, + { title=>' ' }, + { title=>'Overview', url=>'myaccount', size=>'+1', }, + { title=>' ' }, + { title=>'Purchase', size=>'+1', }, ); +unless ( $pkgnum ) { + push @menu, + { title=>'Purchase additional package', + url=>'customer_order_pkg', 'indent'=>2 }; +} + if ( 1 ) { #XXXFIXME "enable selfservice prepay features" flag or something, eventually per-pkg or something really fancy #XXXFIXME still a bit sloppy for multi-gateway of differing namespace @@ -34,7 +37,7 @@ if ( 1 ) { #XXXFIXME "enable selfservice prepay features" flag or something, eve while($i < scalar(@cust_paybys)) { last if $cust_paybys[$i] =~ /^CHEK/; $i++ } if ( $cust_paybys[$i] =~ /^CHEK/ ) { push @menu, { title => 'Recharge my account with a check', - url => $hide_payment_field[$i] + url => $hide_payment_fields[$i] ? 'make_thirdparty_payment&payby_method=ECHECK' : 'make_ach_payment', indent => 2, @@ -49,26 +52,36 @@ if ( 1 ) { #XXXFIXME "enable selfservice prepay features" flag or something, eve } -push @menu, ( - -{ title=>' ' }, +push @menu, + { title=>' ' }, + { title=>'View my usage', url=>'view_usage', size=>'+1', }, +; -{ title=>'View my usage', url=>'view_usage', size=>'+1', }, -{ title=>'Setup my services', url=>'provision', size=>'+1', }, - -{ title=>' ' }, +unless ( $pkgnum ) { + push @menu, + { title=>'Setup my services', url=>'provision', size=>'+1', }, + ; +} -{ title=>'Change my information', size=>'+1', }, - { title=>'Change billing address', url=>'change_bill', indent=>2 }, - { title=>'Change service address', url=>'change_ship', indent=>2 }, - { title=>'Change payment information', url=>'change_pay', indent=>2 }, - { title=>'Change password(s)', url=>'change_password', indent=>2 }, +push @menu, + { title=>' ' }; -{ title=>' ' }, +push @menu, + { title=>'Change my information', size=>'+1', }; -{ title=>'Logout', url=>'logout', size=>'+1', }, +unless ( $pkgnum ) { + push @menu, + { title=>'Change billing address', url=>'change_bill', indent=>2 }, + { title=>'Change service address', url=>'change_ship', indent=>2 }, + { title=>'Change payment information', url=>'change_pay', indent=>2 }, + ; +} -); +push @menu, + { title=>'Change password(s)', url=>'change_password', indent=>2 }, + { title=>' ' }, + { title=>'Logout', url=>'logout', size=>'+1', }, +; foreach my $item ( @menu ) { @@ -83,15 +96,15 @@ foreach my $item ( @menu ) { } $OUT.='>'; - $OUT .= '' - if exists $item->{'size'}; - $OUT .= ' ' x $item->{'indent'} if exists $item->{'indent'}; $OUT .= '' if exists $item->{'url'} && $action ne $item->{'url'}; + $OUT .= '' + if exists $item->{'size'}; + $item->{'title'} =~ s/ / /g; $OUT .= $item->{'title'}; diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi index 09cfe6073..a5a7d1844 100644 --- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi +++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi @@ -10,7 +10,7 @@ use HTML::Entities; use Date::Format; use Number::Format 1.50; use FS::SelfService qw( - skin_info login_info login customer_info edit_info invoice + access_info login_info login customer_info edit_info invoice payment_info process_payment realtime_collect process_prepay list_pkgs order_pkg signup_info order_recharge part_svc_info provision_acct provision_external @@ -98,7 +98,7 @@ warn "processing template $action\n" do_template($action, { 'session_id' => $session_id, 'action' => $action, #so the menu knows what tab we're on... - %{ payment_info( 'session_id' => $session_id ) }, # cust_paybys for the menu + #%{ payment_info( 'session_id' => $session_id ) }, # cust_paybys for the menu %{$result} }); @@ -645,8 +645,10 @@ sub do_template { $fill_in->{'selfurl'} = $cgi->self_url; $fill_in->{'cgi'} = \$cgi; - my $skin_info = skin_info(); - $fill_in->{$_} = $skin_info->{$_} foreach keys %$skin_info; + my $access_info = $session_id + ? access_info( 'session_id' => $session_id ) + : {}; + $fill_in->{$_} = $access_info->{$_} foreach keys %$access_info; my $source = "$template_dir/$name.html"; #warn "creating template for $source\n"; -- cgit v1.2.1 From 903fe2fe14cebb5d311d43edfc60d3c36333e146 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 10 Aug 2009 11:57:14 +0000 Subject: when using pkg-balances, limit self-service access when a customer with multiple packages logs on, RT#4189 --- fs_selfservice/FS-SelfService/cgi/process_svc_external.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_external.html b/fs_selfservice/FS-SelfService/cgi/process_svc_external.html index 1d2937b3e..103eb9e35 100644 --- a/fs_selfservice/FS-SelfService/cgi/process_svc_external.html +++ b/fs_selfservice/FS-SelfService/cgi/process_svc_external.html @@ -1,12 +1,8 @@ -<%= $error ? 'MyAccount' : sprintf("Your serial number is %010d-$title", $id) %> -MyAccount

<%= $url = "$selfurl?session=$session_id;action="; ''; %> -<%= include('myaccount_menu') %> - +<%= include('header') %> <%= $svc %> setup successfully.

Your serial number is <%= sprintf("%010d-$title", $id) %> - <%= include('footer') %> -- cgit v1.2.1 From 7aed8d03d957ee46c71a679ab6fe906d27b33550 Mon Sep 17 00:00:00 2001 From: mark Date: Mon, 10 Aug 2009 18:05:50 +0000 Subject: Add preset for magicmail --- FS/FS/part_export/shellcommands_withdomain.pm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/FS/FS/part_export/shellcommands_withdomain.pm b/FS/FS/part_export/shellcommands_withdomain.pm index e1f47e410..448f0b77b 100644 --- a/FS/FS/part_export/shellcommands_withdomain.pm +++ b/FS/FS/part_export/shellcommands_withdomain.pm @@ -87,6 +87,17 @@ the same username with different domains. You will need to this.form.usermod_stdin.value = ""; this.form.usermod_pwonly.checked = true; '> +
  • The following variables are available for interpolation (prefixed with -- cgit v1.2.1 From 165423e6ce43f8f87f329330bf92f422e718a768 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 10 Aug 2009 21:44:08 +0000 Subject: last nits on netsapiens export, RT#5226 --- FS/FS/part_export/netsapiens.pm | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/FS/FS/part_export/netsapiens.pm b/FS/FS/part_export/netsapiens.pm index a24bc3727..cf4b5e35c 100644 --- a/FS/FS/part_export/netsapiens.pm +++ b/FS/FS/part_export/netsapiens.pm @@ -85,10 +85,6 @@ sub ns_subscriber { sub ns_registrar { my($self, $svc_phone) = (shift, shift); - my $domain = $self->option('domain'); - my $countrycode = $svc_phone->countrycode; - my $phonenum = $svc_phone->phonenum; - $self->ns_subscriber($svc_phone). '/registrar_config/'. $self->ns_devicename($svc_phone); } @@ -97,19 +93,21 @@ sub ns_devicename { my( $self, $svc_phone ) = (shift, shift); my $domain = $self->option('domain'); - my $countrycode = $svc_phone->countrycode; + #my $countrycode = $svc_phone->countrycode; my $phonenum = $svc_phone->phonenum; - "sip:$countrycode$phonenum@$domain"; + #"sip:$countrycode$phonenum\@$domain"; + "sip:$phonenum\@$domain"; } sub ns_dialplan { my($self, $svc_phone) = (shift, shift); - my $countrycode = $svc_phone->countrycode; + #my $countrycode = $svc_phone->countrycode; my $phonenum = $svc_phone->phonenum; - "/dialplans/DID+Table/dialplan_config/sip:$countrycode$phonenum@*" + #"/dialplans/DID+Table/dialplan_config/sip:$countrycode$phonenum\@*" + "/dialplans/DID+Table/dialplan_config/sip:$phonenum\@*" } sub ns_device { @@ -125,7 +123,7 @@ sub ns_create_or_update { my($self, $svc_phone, $dial_policy) = (shift, shift, shift); my $domain = $self->option('domain'); - my $countrycode = $svc_phone->countrycode; + #my $countrycode = $svc_phone->countrycode; my $phonenum = $svc_phone->phonenum; my( $firstname, $lastname ); @@ -158,6 +156,7 @@ sub ns_create_or_update { #Piece 2 - sip device creation my $ns2 = $self->ns_command( 'PUT', $self->ns_registrar($svc_phone), + 'termination_match' => $self->ns_devicename($svc_phone) ); if ( $ns2->responseCode !~ /^2/ ) { @@ -168,7 +167,7 @@ sub ns_create_or_update { #Piece 3 - DID mapping to user my $ns3 = $self->ns_command( 'PUT', $self->ns_dialplan($svc_phone), - 'to_user' => $countrycode.$phonenum, + 'to_user' => $phonenum, 'to_host' => $domain, ); @@ -250,7 +249,7 @@ sub export_device_insert { 'PUT', $self->ns_device($svc_phone, $phone_device), 'line1_enable' => 'yes', 'device1' => $self->ns_devicename($svc_phone), - 'line1_ext' => $countrycode.$phonenum, + 'line1_ext' => $phonenum, , #'line2_enable' => 'yes', #'device2' => -- cgit v1.2.1 From ae898cc8e6de40fbecb30c973f91cd955434b159 Mon Sep 17 00:00:00 2001 From: mark Date: Mon, 10 Aug 2009 23:04:57 +0000 Subject: Improve handling of deleted attachments --- FS/FS/AccessRight.pm | 4 ++ httemplate/edit/cust_main_attach.cgi | 5 +- httemplate/edit/process/cust_main_attach.cgi | 23 +++++-- httemplate/view/attachment.html | 6 +- httemplate/view/cust_main.cgi | 12 +++- httemplate/view/cust_main/attachments.html | 90 +++++++++++++++++----------- 6 files changed, 92 insertions(+), 48 deletions(-) diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index d19212520..17d2d76fd 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -103,6 +103,10 @@ tie my %rights, 'Tie::IxHash', 'Download attachment', #NEW 'Add attachment', #NEW 'Edit attachment', #NEW + 'Delete attachment', #NEW + 'View deleted attachments', #NEW + 'Undelete attachment', #NEW + 'Purge attachment', #NEW 'Bill customer now', #NEW 'Bulk send customer notices', #NEW ], diff --git a/httemplate/edit/cust_main_attach.cgi b/httemplate/edit/cust_main_attach.cgi index 7c9e407d9..dd460fa5e 100755 --- a/httemplate/edit/cust_main_attach.cgi +++ b/httemplate/edit/cust_main_attach.cgi @@ -24,7 +24,7 @@ Filename
    "> -% if(defined $attach) { +% if(defined $attach and $curuser->access_right('Delete attachment')) {
    % } @@ -35,6 +35,7 @@ Filename
    <%init> +my $curuser = $FS::CurrentUser::CurrentUser; my $attachnum = ''; my $attach; if ( $cgi->param('error') ) { @@ -52,7 +53,7 @@ my $custnum = $1; my $action = $attachnum ? 'Edit' : 'Add'; die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right("$action customer note"); + unless $curuser->access_right("$action customer note"); diff --git a/httemplate/edit/process/cust_main_attach.cgi b/httemplate/edit/process/cust_main_attach.cgi index 51eead076..98f4d0912 100644 --- a/httemplate/edit/process/cust_main_attach.cgi +++ b/httemplate/edit/process/cust_main_attach.cgi @@ -4,6 +4,7 @@ %} else { % my $act = 'added'; % $act = 'updated' if ($attachnum); +% $act = 'purged' if($attachnum and $purge); % $act = 'undeleted' if($attachnum and $undelete); % $act = 'deleted' if($attachnum and $delete); <% header('Attachment ' . $act ) %> @@ -23,12 +24,13 @@ $cgi->param('attachnum') =~ /^(\d*)$/ or die "Illegal attachnum: ". $cgi->param('attachnum'); my $attachnum = $1; -my $otaker = $FS::CurrentUser::CurrentUser->name; -$otaker = $FS::CurrentUser::CurrentUser->username - if ($otaker eq "User, Legacy"); +my $curuser = $FS::CurrentUser::CurrentUser; +my $otaker = $curuser->name; +$otaker = $curuser->username if ($otaker eq "User, Legacy"); my $delete = $cgi->param('delete'); my $undelete = $cgi->param('undelete'); +my $purge = $cgi->param('purge'); my $new = new FS::cust_attachment ( { attachnum => $attachnum, @@ -44,6 +46,8 @@ if($attachnum) { if(!$old) { $error = "Attachnum '$attachnum' not found"; } + elsif($purge) { # do nothing + } else { map { $new->$_($old->$_) } ('_date', 'otaker', 'body', 'disabled'); @@ -72,12 +76,19 @@ else { # This is a new attachment, so require a file. $error = 'No file uploaded'; } } -my $user = $FS::CurrentUser::CurrentUser; +my $action = 'Add'; +$action = 'Edit' if $attachnum; +$action = 'Delete' if $attachnum and $delete; +$action = 'Undelete' if $attachnum and $undelete; +$action = 'Purge' if $attachnum and $purge; -$error = 'access denied' unless $user->access_right(($old ? 'Edit' : 'Add') . ' attachment'); +$error = 'access denied' unless $curuser->access_right($action . ' attachment'); if(!$error) { - if($old) { + if($old and $old->disabled and $purge) { + $error = $old->delete; + } + elsif($old) { $error = $new->replace($old); } else { diff --git a/httemplate/view/attachment.html b/httemplate/view/attachment.html index c85b1375f..5fc053967 100644 --- a/httemplate/view/attachment.html +++ b/httemplate/view/attachment.html @@ -1,16 +1,16 @@ +<% $attach->body %> <%init> my ($query) = $cgi->keywords; $query =~ /^(\d+)$/; my $attachnum = $1 or die 'Invalid attachment number'; $FS::CurrentUser::CurrentUser->access_right('Download attachment') or die 'access denied'; -my $attach = qsearchs('cust_attachment', { attachnum => $attachnum }) or die 'Attachment not found: $attachnum'; +my $attach = qsearchs('cust_attachment', { attachnum => $attachnum }) or die "Attachment not found: $attachnum"; +die 'access denied' if $attach->disabled; $m->clear_buffer; $r->content_type($attach->mime_type || 'text/plain'); $r->headers_out->add('Content-Disposition' => 'attachment;filename=' . $attach->filename); -binmode STDOUT; -print STDOUT $attach->body; diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index da1a56a96..bbdfe5166 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -108,7 +108,7 @@ Comments

    % } - +
    % my $notecount = scalar($cust_main->notes()); % if ( ! $conf->exists('cust_main-disable_notes') || $notecount) { @@ -152,6 +152,16 @@ Comments %> % } <% include('cust_main/attachments.html', 'custnum' => $cust_main->custnum ) %> +% if($cgi->param('show_deleted')) { +">(Show active attachments) +% } +% elsif($curuser->access_right('View deleted attachments')) { +">(Show deleted attachments) +% }
    % } diff --git a/httemplate/view/cust_main/attachments.html b/httemplate/view/cust_main/attachments.html index e25814ff5..53635fd62 100755 --- a/httemplate/view/cust_main/attachments.html +++ b/httemplate/view/cust_main/attachments.html @@ -19,9 +19,19 @@ % my $bgcolor1 = '#eeeeee'; % my $bgcolor2 = '#ffffff'; % my $bgcolor = ''; +% if($cgi->param('show_deleted')) { +% if ($curuser->access_right('View deleted attachments')) { +% @attachments = grep { $_->disabled } @attachments; +% } +% else { +% @attachments = (); +% } +% } +% else { +% @attachments = grep { not $_->disabled } @attachments; +% } % -% foreach my $attach ((grep { $_->disabled } @attachments), -% (grep { ! $_->disabled } @attachments)) { +% foreach my $attach (@attachments) { % % if ( $bgcolor eq $bgcolor1 ) { % $bgcolor = $bgcolor2; @@ -32,42 +42,38 @@ % my $pop = popurl(3); % my $attachnum = $attach->attachnum; % my $edit = ''; -% my $download = ''; -% if($attach->disabled) { -% my $onclick = include('/elements/popup_link_onclick.html', -% 'action' => popurl(2). -% 'edit/process/cust_main_attach.cgi'. -% "?custnum=$custnum;". -% "attachnum=$attachnum;". -% "undelete=1", -% 'actionlabel' => 'Undelete attachment', -% 'width' => 616, -% 'height' => 408, -% 'frame' => 'top', -% ); -% my $clickjs = qq!onclick="$onclick"!; -% if($curuser->access_right('Edit attachment')) { -% $edit = qq! (undelete)!; +% if($attach->disabled) { # then you can undelete it or purge it. +% if ($curuser->access_right('Undelete attachment')) { +% my $clickjs = popup('edit/process/cust_main_attach.cgi?'. +% "custnum=$custnum;attachnum=$attachnum;". +% "undelete=1", +% 'Undelete attachment'); +% $edit .= qq!  (undelete)!; +% } +% if ($curuser->access_right('Purge attachment')) { +% my $clickjs = popup('edit/process/cust_main_attach.cgi?'. +% "custnum=$custnum;attachnum=$attachnum;". +% "purge=1", +% 'Purge attachment'); +% $edit .= qq!  (purge)!; % } % } -% else { -% my $onclick = include( '/elements/popup_link_onclick.html', -% 'action' => popurl(2). -% 'edit/cust_main_attach.cgi'. -% "?custnum=$custnum". -% ";attachnum=$attachnum", -% 'actionlabel' => 'Edit customer note', -% 'width' => 616, -% 'height' => 408, -% 'frame' => 'top', -% ); -% my $clickjs = qq!onclick="$onclick"!; -% +% else { # you can download or edit it % if ($curuser->access_right('Edit attachment') ) { -% $edit = qq! (edit)!; +% my $clickjs = popup('edit/cust_main_attach.cgi?'. +% "custnum=$custnum;attachnum=$attachnum", +% 'Edit attachment properties'); +% $edit .= qq!  (edit)!; +% } +% if($curuser->access_right('Delete attachment') ) { +% my $clickjs = popup('edit/process/cust_main_attach.cgi?'. +% "custnum=$custnum;attachnum=$attachnum;". +% "delete=1", +% 'Delete attachment'); +% $edit .= qq!  (delete)!; % } % if ($curuser->access_right('Download attachment') ) { -% $download = qq! (download)!; +% $edit .= qq!  (download)!; % } % } @@ -86,10 +92,8 @@  <% size_units( $attach->size ) %> -  <% $edit %> -  <% $download %> + <% $edit %> - <% $attach->disabled ? '' : '' %> % } #end display notes @@ -130,4 +134,18 @@ sub size_units { return int($bytes / 1048576)."M"; } +sub popup { + my ($url, $label) = @_; + my $onclick = + include('/elements/popup_link_onclick.html', + 'action' => popurl(2).$url, + 'actionlabel' => $label, + 'width' => 616, + 'height' => 408, + 'frame' => 'top', + ); + return qq!onclick="$onclick"!; +} + + -- cgit v1.2.1 From 54538d4a7445f5315e27cb8ff44b5ddc4160ee88 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 11 Aug 2009 02:34:57 +0000 Subject: add $company_name and $company_address to decline template, RT#5869 --- FS/FS/cust_main.pm | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 8cd03ebc6..b8657895b 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -4221,7 +4221,13 @@ sub realtime_bop { $template->compile() or return "($perror) can't compile template: $Text::Template::ERROR"; - my $templ_hash = { error => $transaction->error_message }; + my $templ_hash = { + 'company_name' => + scalar( $conf->config('company_name', $self->agentnum ) ), + 'company_address' => + join("\n", $conf->config('company_address', $self->agentnum ) ), + 'error' => $transaction->error_message, + }; my $error = send_email( 'from' => $conf->config('invoice_from', $self->agentnum ), @@ -5401,7 +5407,13 @@ sub _realtime_bop_result { $template->compile() or return "($perror) can't compile template: $Text::Template::ERROR"; - my $templ_hash = { error => $transaction->error_message }; + my $templ_hash = { + 'company_name' => + scalar( $conf->config('company_name', $self->agentnum ) ), + 'company_address' => + join("\n", $conf->config('company_address', $self->agentnum ) ), + 'error' => $transaction->error_message, + }; my $error = send_email( 'from' => $conf->config('invoice_from', $self->agentnum ), -- cgit v1.2.1 From 66f90856e0b21117a4e62f2bebec0908feda8fda Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 11 Aug 2009 02:45:21 +0000 Subject: fix bad debt writeoff action, RT#5798 --- FS/FS/part_event/Action/writeoff.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FS/FS/part_event/Action/writeoff.pm b/FS/FS/part_event/Action/writeoff.pm index fdea897fa..8529d29f1 100644 --- a/FS/FS/part_event/Action/writeoff.pm +++ b/FS/FS/part_event/Action/writeoff.pm @@ -22,9 +22,9 @@ sub do_action { my $cust_main = $self->cust_main($cust_object); - my $error = $cust_main->credit( $cust_main->balance, - $self->option('reasonnum'), - ); + my $reasonnum = $self->option('reasonnum'); + + my $error = $cust_main->credit( $cust_main->balance, \$reasonnum ); die $error if $error; ''; -- cgit v1.2.1 From 58b83f939fb1d6531ec16533733dbde281d4b2dc Mon Sep 17 00:00:00 2001 From: rsiddall Date: Tue, 11 Aug 2009 21:30:27 +0000 Subject: Reset RPM release number back to 1 on a new version release. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 1795f0459..35d904496 100644 --- a/Makefile +++ b/Makefile @@ -394,6 +394,7 @@ release: # Update the RPM specfile cvs edit ${RPM_SPECFILE} perl -p -i -e "s/\d+[^\}]+/${VERSION}/ if /%define\s+version\s+(\d+[^\}]+)\}/;" ${RPM_SPECFILE} + perl -p -i -e "s/\d+[^\}]+/1/ if /%define\s+release\s+(\d+[^\}]+)\}/;" ${RPM_SPECFILE} cvs commit -m "Updated for ${VERSION}" ${RPM_SPECFILE} # Update the Debian changelog -- cgit v1.2.1 From c670aeaa5896a9d62dd1bd093b4b13dba0a52c68 Mon Sep 17 00:00:00 2001 From: rsiddall Date: Tue, 11 Aug 2009 21:33:09 +0000 Subject: Back out kludge to show CVS snapshot date in version number in GUI. You can get the snapshot date from the release number using "rpm -q freeside". --- rpm/freeside.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpm/freeside.spec b/rpm/freeside.spec index 684f213b9..7bf8abf86 100644 --- a/rpm/freeside.spec +++ b/rpm/freeside.spec @@ -195,7 +195,7 @@ else fi %{__make} OPTIMIZE="$RPM_OPT_FLAGS" cd .. -%{__make} perl-modules VERSION='%{version}-%{release}' RT_ENABLED=%{rt_enabled} FREESIDE_CACHE=%{freeside_cache} FREESIDE_CONF=%{freeside_conf} FREESIDE_EXPORT=%{freeside_export} FREESIDE_LOCK=%{freeside_lock} FREESIDE_LOG=%{freeside_log} +%{__make} perl-modules RT_ENABLED=%{rt_enabled} FREESIDE_CACHE=%{freeside_cache} FREESIDE_CONF=%{freeside_conf} FREESIDE_EXPORT=%{freeside_export} FREESIDE_LOCK=%{freeside_lock} FREESIDE_LOG=%{freeside_log} touch perl-modules cd fs_selfservice/FS-SelfService -- cgit v1.2.1 From d1014a727cefa5d9813153594541f62ec15fc8b9 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 12 Aug 2009 02:36:25 +0000 Subject: fix multiple pkgpart search, RT#5924 --- FS/FS/cust_pkg.pm | 23 +++++++++++++++++++---- httemplate/misc/bulk_change_pkg.cgi | 20 +++++++++++++------- httemplate/search/cust_pkg.cgi | 24 ++++++++++++++---------- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 396ae07cc..4e57fbf2d 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -2295,7 +2295,7 @@ active, inactive, suspended, one-time charge, inactive, cancel (or cancelled) =item pkgpart -list specified how? +pkgpart or arrayref or hashref of pkgparts =item setup @@ -2463,9 +2463,24 @@ sub search_sql { # parse part_pkg ### - my $pkgpart = join (' OR pkgpart=', - grep {$_} map { /^(\d+)$/; } ($params->{'pkgpart'})); - push @where, '(pkgpart=' . $pkgpart . ')' if $pkgpart; + if ( ref($params->{'pkgpart'}) ) { + + my @pkgpart = (); + if ( ref($params->{'pkgpart'}) eq 'HASH' ) { + @pkgpart = grep $params->{'pkgpart'}{$_}, keys %{ $params->{'pkgpart'} }; + } elsif ( ref($params->{'pkgpart'}) eq 'ARRAY' ) { + @pkgpart = @{ $params->{'pkgpart'} }; + } else { + die 'unhandled pkgpart ref '. $params->{'pkgpart'}; + } + + @pkgpart = grep /^(\d+)$/, @pkgpart; + + push @where, 'pkgpart IN ('. join(',', @pkgpart). ')'; + + } elsif ( $params->{'pkgpart'} =~ /^(\d+)$/ ) { + push @where, "pkgpart = $1"; + } ### # parse dates diff --git a/httemplate/misc/bulk_change_pkg.cgi b/httemplate/misc/bulk_change_pkg.cgi index 3bb677581..7f47a84cf 100755 --- a/httemplate/misc/bulk_change_pkg.cgi +++ b/httemplate/misc/bulk_change_pkg.cgi @@ -7,17 +7,23 @@
    - -% for my $param (qw(agentnum magic status classnum pkgpart)) { - +%# some false laziness w/search/cust_pkg.cgi + + +% for my $param (qw(agentnum magic status classnum custom censustract)) { + % } % +% foreach my $pkgpart ($cgi->param('pkgpart')) { + +% } +% % foreach my $field (qw( setup last_bill bill adjourn susp expire cancel )) { % - "> - "> - "> - "> + "> + "> + "> + "> % } <% ntable('#cccccc') %> diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index f6a3620d3..f03bbc26b 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -158,18 +158,22 @@ my $money_char = $conf->config('money_char') || '$'; # my %part_pkg = map { $_->pkgpart => $_ } qsearch('part_pkg', {}); - my %search_hash = (); +my %search_hash = (); + +#some false laziness w/misc/bulk_change_pkg.cgi - $search_hash{'query'} = $cgi->keywords; +$search_hash{'query'} = $cgi->keywords; - for ( qw(agentnum magic status classnum pkgpart custom ) ) { - $search_hash{$_} = $cgi->param($_) if $cgi->param($_); - } - - for my $param ( qw(censustract) ) { - $search_hash{$param} = $cgi->param($param) || '' - if ( grep { /$param/ } $cgi->param ); - } +for (qw( agentnum magic status classnum custom )) { + $search_hash{$_} = $cgi->param($_) if $cgi->param($_); +} + +$search_hash{'pkgpart'} = [ $cgi->param('pkgpart') ]; + +for my $param ( qw(censustract) ) { + $search_hash{$param} = $cgi->param($param) || '' + if ( grep { /$param/ } $cgi->param ); +} my @report_option = $cgi->param('report_option') if $cgi->param('report_option'); -- cgit v1.2.1 From 7aad2eb29c444625fd1130f4ed37d89a7da2c027 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 12 Aug 2009 05:22:08 +0000 Subject: add pre-bill event stage for late fees, RT#5589 --- FS/FS/cust_main.pm | 152 ++++++++++++++++++++--- FS/FS/part_event/Action.pm | 13 ++ FS/FS/part_event/Action/cust_bill_fee_percent.pm | 2 + FS/FS/part_event/Action/fee.pm | 2 + 4 files changed, 153 insertions(+), 16 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index b8657895b..b278e9b14 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2488,7 +2488,6 @@ sub bill { $options{'not_pkgpart'} ||= {}; - #put below somehow? local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; local $SIG{QUIT} = 'IGNORE'; @@ -2502,6 +2501,17 @@ sub bill { $self->select_for_update; #mutex + my $error = $self->do_cust_event( + 'debug' => ( $options{'debug'} || 0 ), + 'time' => $invoice_time, + 'check_freq' => $options{'check_freq'}, + 'stage' => 'pre-bill', + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + my @cust_bill_pkg = (); ### @@ -2755,7 +2765,7 @@ sub bill { '_date' => ( $invoice_time ), 'charged' => $charged, } ); - my $error = $cust_bill->insert; + $error = $cust_bill->insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; return "can't create invoice for customer #". $self->custnum. ": $error"; @@ -3222,7 +3232,7 @@ sub _gather_taxes { } -=item collect OPTIONS +=item collect [ HASHREF | OPTION => VALUE ... ] (Attempt to) collect money for this customer's outstanding invoices (see L). Usually used after the bill method. @@ -3247,25 +3257,24 @@ Use this time when deciding when to print invoices and late notices on those inv Retry card/echeck/LEC transactions even when not scheduled by invoice events. -=item quiet - -set true to surpress email card/ACH decline notices. - =item check_freq "1d" for the traditional, daily events (the default), or "1m" for the new monthly events (part_event.check_freq) -=item payby +=item quiet -allows for one time override of normal customer billing method +set true to surpress email card/ACH decline notices. =item debug Debugging level. Default is 0 (no debugging), or can be set to 1 (passed-in options), 2 (traces progress), 3 (more information), or 4 (include full search queries) - =back +# =item payby +# +# allows for one time override of normal customer billing method + =cut sub collect { @@ -3303,12 +3312,107 @@ sub collect { } } + my $error = $self->do_cust_event( + 'debug' => ( $options{'debug'} || 0 ), + 'time' => $invoice_time, + 'check_freq' => $options{'check_freq'}, + 'stage' => 'collect', + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + +=item do_cust_event [ HASHREF | OPTION => VALUE ... ] + +Runs billing events; see L and the billing events web +interface. + +If there is an error, returns the error, otherwise returns false. + +Options are passed as name-value pairs. + +Currently available options are: + +=over 4 + +=item time + +Use this time when deciding when to print invoices and late notices on those invoices. The default is now. It is specified as a UNIX timestamp; see L). Also see L and L for conversion functions. + +=item check_freq + +"1d" for the traditional, daily events (the default), or "1m" for the new monthly events (part_event.check_freq) + +=item stage + +"collect" (the default) or "pre-bill" + +=item quiet + +set true to surpress email card/ACH decline notices. + +=item debug + +Debugging level. Default is 0 (no debugging), or can be set to 1 (passed-in options), 2 (traces progress), 3 (more information), or 4 (include full search queries) + +=cut + +# =item payby +# +# allows for one time override of normal customer billing method + +# =item retry +# +# Retry card/echeck/LEC transactions even when not scheduled by invoice events. + +sub do_cust_event { + my( $self, %options ) = @_; + my $time = $options{'time'} || time; + + #put below somehow? + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + $self->select_for_update; #mutex + + if ( $DEBUG ) { + my $balance = $self->balance; + warn "$me do_cust_event customer ". $self->custnum. ": balance $balance\n" + } + +# if ( exists($options{'retry_card'}) ) { +# carp 'retry_card option passed to collect is deprecated; use retry'; +# $options{'retry'} ||= $options{'retry_card'}; +# } +# if ( exists($options{'retry'}) && $options{'retry'} ) { +# my $error = $self->retry_realtime; +# if ( $error ) { +# $dbh->rollback if $oldAutoCommit; +# return $error; +# } +# } + # false laziness w/pay_batch::import_results my $due_cust_event = $self->due_cust_event( 'debug' => ( $options{'debug'} || 0 ), - 'time' => $invoice_time, + 'time' => $time, 'check_freq' => $options{'check_freq'}, + 'stage' => ( $options{'stage'} || 'collect' ), ); unless( ref($due_cust_event) ) { $dbh->rollback if $oldAutoCommit; @@ -3320,7 +3424,7 @@ sub collect { #XXX lock event #re-eval event conditions (a previous event could have changed things) - unless ( $cust_event->test_conditions( 'time' => $invoice_time ) ) { + unless ( $cust_event->test_conditions( 'time' => $time ) ) { #don't leave stray "new/locked" records around my $error = $cust_event->delete; if ( $error ) { @@ -3373,6 +3477,10 @@ options are: Search only for events of this check frequency (how often events of this type are checked); currently "1d" (daily, the default) and "1m" (monthly) are recognized. +=item stage + +"collect" (the default) or "pre-bill" + =item time "Current time" for the events. @@ -3428,7 +3536,7 @@ sub due_cust_event { unless $opt{testonly}; ### - # 1: find possible events (initial search) + # find possible events (initial search) ### my @cust_event = (); @@ -3519,8 +3627,20 @@ sub due_cust_event { " total possible cust events found in initial search\n" if $DEBUG; # > 1; + + ## + # test stage + ## + + $opt{stage} ||= 'collect'; + @cust_event = + grep { my $stage = $_->part_event->event_stage; + $opt{stage} eq $stage or ( ! $stage && $opt{stage} eq 'collect' ) + } + @cust_event; + ## - # 2: test conditions + # test conditions ## my %unsat = (); @@ -3537,7 +3657,7 @@ sub due_cust_event { if $DEBUG; # > 1; ## - # 3: insert + # insert ## unless( $opt{testonly} ) { @@ -3555,7 +3675,7 @@ sub due_cust_event { $dbh->commit or die $dbh->errstr if $oldAutoCommit; ## - # 4: return + # return ## warn " returning events: ". Dumper(@cust_event). "\n" diff --git a/FS/FS/part_event/Action.pm b/FS/FS/part_event/Action.pm index 57239d78e..45219a321 100644 --- a/FS/FS/part_event/Action.pm +++ b/FS/FS/part_event/Action.pm @@ -54,6 +54,19 @@ sub eventtable_hashref { }; } +=item event_stage + +Action classes may define an event_stage method to indicate a preference +for being run at a non-standard stage of the billing and collection process. + +This method may currently return "collect" (the default) or "pre-bill". + +=cut + +sub event_stage { + 'collect'; +} + =item option_fields Action classes may define an option_fields method to indicate that they diff --git a/FS/FS/part_event/Action/cust_bill_fee_percent.pm b/FS/FS/part_event/Action/cust_bill_fee_percent.pm index 354778f7d..9206c6a33 100644 --- a/FS/FS/part_event/Action/cust_bill_fee_percent.pm +++ b/FS/FS/part_event/Action/cust_bill_fee_percent.pm @@ -9,6 +9,8 @@ sub eventtable_hashref { { 'cust_bill' => 1 }; } +sub event_stage { 'pre-bill'; } + sub option_fields { ( 'percent' => { label=>'Percent', size=>2, }, diff --git a/FS/FS/part_event/Action/fee.pm b/FS/FS/part_event/Action/fee.pm index 6ea7103ab..6450225a2 100644 --- a/FS/FS/part_event/Action/fee.pm +++ b/FS/FS/part_event/Action/fee.pm @@ -5,6 +5,8 @@ use base qw( FS::part_event::Action ); sub description { 'Late fee (flat)'; } +sub event_stage { 'pre-bill'; } + sub option_fields { ( 'charge' => { label=>'Amount', type=>'money', }, # size=>7, }, -- cgit v1.2.1 From 600a15aa56c212e1206fced9cbcf9de103c2f95b Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 12 Aug 2009 11:58:21 +0000 Subject: slight about/credits UI tweak --- httemplate/docs/about.html | 4 ++-- httemplate/docs/credits.html | 4 +--- httemplate/docs/license.html | 6 +++--- httemplate/elements/header-popup.html | 33 ++++++++++++++++++++++++++------- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/httemplate/docs/about.html b/httemplate/docs/about.html index fbf0a66f5..04af73db8 100644 --- a/httemplate/docs/about.html +++ b/httemplate/docs/about.html @@ -1,9 +1,9 @@ -<% include('/elements/header-popup.html', 'Freeside') %> +<% include('/elements/header-popup.html', { title=>'Freeside', nobr=>1 } ) %> <% include('/elements/init_overlib.html') %>
    -
    +

    version <% $FS::VERSION %>

    diff --git a/httemplate/docs/credits.html b/httemplate/docs/credits.html index a944f48fa..d927722e0 100644 --- a/httemplate/docs/credits.html +++ b/httemplate/docs/credits.html @@ -24,10 +24,8 @@
    Freeside
    -
    -
    -
    +

    version <% $FS::VERSION %>

    diff --git a/httemplate/docs/license.html b/httemplate/docs/license.html index a673bc9dd..fc3da6913 100644 --- a/httemplate/docs/license.html +++ b/httemplate/docs/license.html @@ -1,12 +1,12 @@ -<% include('/elements/header-popup.html', 'Freeside') %> +<% include('/elements/header-popup.html', { title=>'Freeside', nobr=>1 } ) %>
    -
    +

    version <% $FS::VERSION %>

    -Copyright © 2005-2008 Freeside Internet Services, Inc.
    +Copyright © 2005-2009 Freeside Internet Services, Inc.
    Copyright © 2000-2005 Ivan Kohler
    Copyright © 1999 Silicon Interactive Software Design
    All rights reserved
    diff --git a/httemplate/elements/header-popup.html b/httemplate/elements/header-popup.html index 68be108d2..d74581b07 100644 --- a/httemplate/elements/header-popup.html +++ b/httemplate/elements/header-popup.html @@ -1,10 +1,3 @@ -% -% my($title, $menubar) = ( shift, shift ); #$menubar is unused here though -% my $etc = @_ ? shift : ''; #$etc is for things like onLoad= etc. -% my $head = @_ ? shift : ''; #$head is for things that go in the section -% my $conf = new FS::Conf; -% - @@ -21,4 +14,30 @@

    <% $title %>
    + +% unless ( $nobr ) {
    +% } + +<%init> + +my( $title, $menubar, $etc, $head ) = ( '', '', '', '' ); +#my( $nobr, $nocss ) = ( 0, 0 ); +my $nobr = 0; +if ( ref($_[0]) ) { + my $opt = shift; + $title = $opt->{title}; + $menubar = $opt->{menubar}; + $etc = $opt->{etc}; + $head = $opt->{head}; + $nobr = $opt->{nobr}; +# $nocss = $opt->{nocss}; +} else { + ($title, $menubar) = ( shift, shift ); + $etc = @_ ? shift : ''; #$etc is for things like onLoad= etc. + $head = @_ ? shift : ''; #$head is for things that go in the section +} + +my $conf = new FS::Conf; + + -- cgit v1.2.1 From 56a2965996454a0649d43ecbc062beda61106e21 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 12 Aug 2009 14:58:50 +0000 Subject: internalize billco-upload and automate the transfer to the provider RT#5902 --- FS/FS/Conf.pm | 72 ++++++++++++---- FS/FS/Cron/upload.pm | 176 ++++++++++++++++++++++++++++++++++++++ FS/bin/freeside-daily | 4 + FS/bin/freeside-monthly | 3 + Makefile | 1 + bin/billco-upload | 40 --------- httemplate/config/config-view.cgi | 22 ++--- 7 files changed, 246 insertions(+), 72 deletions(-) create mode 100644 FS/FS/Cron/upload.pm delete mode 100644 bin/billco-upload diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 1da55837c..66d8be903 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -76,11 +76,23 @@ sub base_dir { $1; } -=item config KEY [ AGENTNUM ] +=item conf KEY [ AGENTNUM [ NODEFAULT ] ] + +Returns the L record for the key and agent. + +=cut + +sub conf { + my $self = shift; + $self->_config(@_); +} + +=item config KEY [ AGENTNUM [ NODEFAULT ] ] Returns the configuration value or values (depending on context) for key. The optional agent number selects an agent specific value instead of the -global default if one is present. +global default if one is present. If NODEFAULT is true only the agent +specific value(s) is returned. =cut @@ -92,14 +104,13 @@ sub _usecompat { $compat->$method(@_); } -# needs a non _ name, called externally by config-view now (and elsewhere?) sub _config { - my($self,$name,$agentnum)=@_; + my($self,$name,$agentnum,$agentonly)=@_; my $hashref = { 'name' => $name }; $hashref->{agentnum} = $agentnum; local $FS::Record::conf = undef; # XXX evil hack prevents recursion my $cv = FS::Record::qsearchs('conf', $hashref); - if (!$cv && defined($agentnum) && $agentnum) { + if (!$agentonly && !$cv && defined($agentnum) && $agentnum) { $hashref->{agentnum} = ''; $cv = FS::Record::qsearchs('conf', $hashref); } @@ -110,12 +121,10 @@ sub config { my $self = shift; return $self->_usecompat('config', @_) if use_confcompat; - my($name, $agentnum)=@_; - - carp "FS::Conf->config($name, $agentnum) called" + carp "FS::Conf->config(". join(', ', @_). ") called" if $DEBUG > 1; - my $cv = $self->_config($name, $agentnum) or return; + my $cv = $self->_config(@_) or return; if ( wantarray ) { my $v = $cv->value; @@ -126,7 +135,7 @@ sub config { } } -=item config_binary KEY [ AGENTNUM ] +=item config_binary KEY [ AGENTNUM [ NODEFAULT ] ] Returns the exact scalar value for key. @@ -136,12 +145,11 @@ sub config_binary { my $self = shift; return $self->_usecompat('config_binary', @_) if use_confcompat; - my($name,$agentnum)=@_; - my $cv = $self->_config($name, $agentnum) or return; + my $cv = $self->_config(@_) or return; decode_base64($cv->value); } -=item exists KEY [ AGENTNUM ] +=item exists KEY [ AGENTNUM [ NODEFAULT ] ] Returns true if the specified key exists, even if the corresponding value is undefined. @@ -154,10 +162,10 @@ sub exists { my($name, $agentnum)=@_; - carp "FS::Conf->exists($name, $agentnum) called" + carp "FS::Conf->exists(". join(', ', @_). ") called" if $DEBUG > 1; - defined($self->_config($name, $agentnum)); + defined($self->_config(@_)); } =item config_orbase KEY SUFFIX @@ -619,6 +627,40 @@ worry that config_items is freeside-specific and icky. 'type' => 'textarea', }, + { + 'key' => 'billco-url', + 'section' => 'billing', + 'description' => 'The url to use for performing uploads to the invoice mailing service.', + 'type' => 'text', + 'per_agent' => 1, + }, + + { + 'key' => 'billco-username', + 'section' => 'billing', + 'description' => 'The login name to use for uploads to the invoice mailing service.', + 'type' => 'text', + 'per_agent' => 1, + 'agentonly' => 1, + }, + + { + 'key' => 'billco-password', + 'section' => 'billing', + 'description' => 'The password to use for uploads to the invoice mailing service.', + 'type' => 'text', + 'per_agent' => 1, + 'agentonly' => 1, + }, + + { + 'key' => 'billco-clicode', + 'section' => 'billing', + 'description' => 'The clicode to use for uploads to the invoice mailing service.', + 'type' => 'text', + 'per_agent' => 1, + }, + { 'key' => 'business-onlinepayment', 'section' => 'billing', diff --git a/FS/FS/Cron/upload.pm b/FS/FS/Cron/upload.pm new file mode 100644 index 000000000..fea3d2cc7 --- /dev/null +++ b/FS/FS/Cron/upload.pm @@ -0,0 +1,176 @@ +package FS::Cron::upload; + +use strict; +use vars qw( @ISA @EXPORT_OK $me $DEBUG ); +use Exporter; +use Date::Format; +use FS::UID qw(dbh); +use FS::Record qw( qsearch qsearchs ); +use FS::Conf; +use FS::queue; +use FS::agent; +use LWP::UserAgent; +use HTTP::Request; +use HTTP::Request::Common; +use HTTP::Response; + +@ISA = qw( Exporter ); +@EXPORT_OK = qw ( upload ); +$DEBUG = 0; +$me = '[FS::Cron::upload]'; + +#freeside-daily %opt: +# -v: enable debugging +# -l: debugging level +# -m: Experimental multi-process mode uses the job queue for multi-process and/or multi-machine billing. +# -r: Multi-process mode dry run option +# -a: Only process customers with the specified agentnum + + +sub upload { + my %opt = @_; + + my $debug = 0; + $debug = 1 if $opt{'v'}; + $debug = $opt{'l'} if $opt{'l'}; + + local $DEBUG = $debug if $debug; + + warn "$me upload called\n" if $DEBUG; + + my $conf = new FS::Conf; + my @agent = grep { $conf->config( 'billco-username', $_->agentnum, 1 ) } + grep { $conf->config( 'billco-password', $_->agentnum, 1 ) } + qsearch( 'agent', {} ); + + my $date = time2str('%Y%m%d%H%M%S', $^T); # more? + + @agent = grep { $_ == $opt{'a'} } @agent if $opt{'a'}; + + foreach my $agent ( @agent ) { + + my $agentnum = $agent->agentnum; + + if ( $opt{'m'} ) { + + if ( $opt{'r'} ) { + warn "DRY RUN: would add agent $agentnum for queued upload\n"; + } else { + + my $queue = new FS::queue { + 'job' => 'FS::Cron::upload::billco_upload', + }; + my $error = $queue->insert( + 'agentnum' => $agentnum, + 'date' => $date, + 'l' => $opt{'l'} || '', + 'm' => $opt{'m'} || '', + 'v' => $opt{'v'} || '', + ); + + } + + } else { + + eval "&billco_upload( 'agentnum' => $agentnum, 'date' => $date );"; + warn "billco_upload failed: $@\n" + if ( $@ ); + + } + + } + +} + +sub billco_upload { + my %opt = @_; + + warn "$me billco_upload called\n" if $DEBUG; + my $conf = new FS::Conf; + my $dir = '%%%FREESIDE_EXPORT%%%/export.'. $FS::UID::datasrc. '/cust_bill'; + + my $agentnum = $opt{agentnum} or die "no agentnum provided\n"; + my $url = $conf->config( 'billco-url', $agentnum ) + or die "no url for agent $agentnum\n"; + my $username = $conf->config( 'billco-username', $agentnum, 1 ) + or die "no username for agent $agentnum\n"; + my $password = $conf->config( 'billco-password', $agentnum, 1 ) + or die "no password for agent $agentnum\n"; + my $clicode = $conf->config( 'billco-clicode', $agentnum ) + or die "no clicode for agent $agentnum\n"; + + die "no date provided\n" unless $opt{date}; + my $zipfile = "$dir/agentnum$agentnum-$opt{date}.zip"; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $agent = qsearchs( 'agent', { agentnum => $agentnum } ) + or die "no such agent: $agentnum"; + $agent->select_for_update; #mutex + + unless ( -f "$dir/agentnum$agentnum-header.csv" || + -f "$dir/agentnum$agentnum-detail.csv" ) + { + warn "$me neither $dir/agentnum$agentnum-header.csv nor ". + "$dir/agentnum$agentnum-detail.csv found\n" if $DEBUG; + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + return; + } + + # a better way? + if ($opt{m}) { + my $sql = "SELECT count(*) FROM queue LEFT JOIN cust_main USING(custnum) ". + "WHERE queue.job='FS::cust_main::queued_bill' AND cust_main.agentnum = ?"; + my $sth = $dbh->prepare($sql) or die $dbh->errstr; + while (1) { + $sth->execute( $agentnum ) + or die "Unexpected error executing statement $sql: ". $sth->errstr; + last if $sth->fetchow_arrayref->[0]; + sleep 300; + } + } + + foreach ( qw ( header detail ) ) { + rename "$dir/agentnum$agentnum-$_.csv", + "$dir/agentnum$agentnum-$opt{date}-$_.csv"; + } + + my $command = "cd $dir; zip $zipfile ". + "agentnum$agentnum-$opt{date}-header.csv ". + "agentnum$agentnum-$opt{date}-detail.csv"; + + system($command) and die "$command failed\n"; + + unlink "agentnum$agentnum-$opt{date}-header.csv", + "agentnum$agentnum-$opt{date}-detail.csv"; + + my $ua = new LWP::UserAgent; + my $res = $ua->request( POST( $url, + 'Content_Type' => 'form-data', + 'Content' => [ 'username' => $username, + 'pass' => $password, + 'custid' => $username, + 'clicode' => $clicode, + 'file1' => [ $zipfile ], + ], + ) + ); + + die "upload failed: ". $res->status_line. "\n" + unless $res->is_success; + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + +1; diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily index 119f93a59..728fa969a 100755 --- a/FS/bin/freeside-daily +++ b/FS/bin/freeside-daily @@ -15,6 +15,10 @@ adminsuidsetup $user; use FS::Cron::bill qw(bill); bill(%opt); +#you can skip this just by not having the config +use FS::Cron::upload qw(upload); +upload(%opt); + # Send alerts about upcoming credit card expiration. use FS::Cron::alert_expiration qw(alert_expiration); my $conf = new FS::Conf; diff --git a/FS/bin/freeside-monthly b/FS/bin/freeside-monthly index 1e41b780e..a81e3e9ed 100755 --- a/FS/bin/freeside-monthly +++ b/FS/bin/freeside-monthly @@ -15,6 +15,9 @@ adminsuidsetup $user; use FS::Cron::bill qw(bill); bill(%opt, 'check_freq'=>'1m' ); +use FS::Cron::upload qw(upload); +upload(%opt); + ### # subroutines ### diff --git a/Makefile b/Makefile index 35d904496..79135e7a7 100644 --- a/Makefile +++ b/Makefile @@ -200,6 +200,7 @@ perl-modules: perl -p -i -e "\ s/%%%SELFSERVICE_USER%%%/${SELFSERVICE_USER}/g;\ s/%%%SELFSERVICE_MACHINES%%%/${SELFSERVICE_MACHINES}/g;\ + s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ " blib/lib/FS/Cron/*.pm;\ perl -p -i -e "\ s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ diff --git a/bin/billco-upload b/bin/billco-upload deleted file mode 100644 index 3a02ec8bb..000000000 --- a/bin/billco-upload +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -AGENTNUMS="1 2 3 5 8 9 10" - -date=`date +"%Y%m%d"` -dir="/usr/local/etc/freeside/export.DBI:Pg:dbname=freeside/cust_bill" -lock=".billco-upload.lock" -cd "$dir" - -failed_mutex() -{ - echo "billco-upload already running; exiting" - exit 1 -} - -#acquire mutex -[ -f $lock ] && { - failed_mutex -} || { - echo $$ > $lock - [ $(cat $lock 2>/dev/null) -eq $$ ] || failed_mutex -} - -for AGENTNUM in $AGENTNUMS; do - - for a in header detail; do - mv agentnum$AGENTNUM-$a.csv agentnum$AGENTNUM-$date-$a.csv - done - - zip agentnum$AGENTNUM-$date.zip agentnum$AGENTNUM-$date-header.csv agentnum$AGENTNUM-$date-detail.csv - -# Remove if trying to find problems with billco upload files - rm *$AGENTNUM-$date*.csv - - echo $dir/agentnum$AGENTNUM-$date.zip - -done - -#release mutex -rm -f $lock diff --git a/httemplate/config/config-view.cgi b/httemplate/config/config-view.cgi index 9e9e64eb2..0f6c99232 100644 --- a/httemplate/config/config-view.cgi +++ b/httemplate/config/config-view.cgi @@ -66,7 +66,7 @@ Click on a configuration value to change it. % @agents = ( '' ); % if ( $i->per_agent ) { % foreach my $agent (@all_agents) { -% if ( defined(_config_agentonly($conf, $i->key, $agent->agentnum)) ) { +% if ( defined($conf->conf( $i->key, $agent->agentnum, 1 ) ) ) { % push @agents, $agent; % } else { % push @add_agents, $agent; @@ -99,15 +99,14 @@ Click on a configuration value to change it. ) %>: <% $i->description %> % if ( $agent && $cgi->param('showagent') ) { -% my $confnum = -% _config_agentonly($conf, $i->key, $agent->agentnum)->confnum; +% my $confnum = $conf->conf( $i->key, $agent->agentnum, 1 )->confnum; (delete agent override) % } elsif ( $i->base_key % || ( $deleteable{$i->key} && $conf->exists($i->key) ) ) { % my $confnum = % $agent -% ? _config_agentonly($conf, $i->key, $agent->agentnum)->confnum -% : $conf->_config( $i->key )->confnum; +% ? $conf->conf( $i->key, $agent->agentnum, 1 )->confnum +% : $conf->conf( $i->key )->confnum; % my $showagent = $cgi->param('showagent') ? '_showagent' : ''; (delete configuration item) % } @@ -286,18 +285,6 @@ Click on a configuration value to change it. -<%once> - -#should probably be a Conf method. what else would need to use it? -sub _config_agentonly { - my($self,$name,$agentnum)=@_; - my $hashref = { 'name' => $name }; - $hashref->{agentnum} = $agentnum; - local $FS::Record::conf = undef; # XXX evil hack prevents recursion - FS::Record::qsearchs('conf', $hashref); -} - - <%init> die "access denied" @@ -320,6 +307,7 @@ if ($cgi->param('agentnum') =~ /^(\d+)$/) { my $conf = new FS::Conf; my @config_items = grep { $page_agent ? $_->per_agent : 1 } + grep { $page_agent ? 1 : !$_->agentonly } $conf->config_items; my @deleteable = qw( invoice_latexreturnaddress invoice_htmlreturnaddress ); -- cgit v1.2.1 From 50410b4b100da824f4fa68316fb82ee76cfaee95 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 13 Aug 2009 00:26:15 +0000 Subject: useful stuff for webdemo & profiling --- init.d/freeside-init | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/init.d/freeside-init b/init.d/freeside-init index 4e58b32df..b4609d48a 100644 --- a/init.d/freeside-init +++ b/init.d/freeside-init @@ -8,6 +8,8 @@ QUEUED_USER=%%%QUEUED_USER%%% SELFSERVICE_USER=%%%SELFSERVICE_USER%%% SELFSERVICE_MACHINES="%%%SELFSERVICE_MACHINES%%%" +IF=eth0 + #INSTALLSCRIPT/INSTALLSITEBIN from Makefile.PL PATH="$PATH:/usr/local/bin" export PATH @@ -20,6 +22,8 @@ case "$1" in echo -n "Starting freeside-queued: " #perl -MDBIx::Profile /usr/local/bin/freeside-queued $QUEUED_USER freeside-queued $QUEUED_USER + #export NYTPROF="file=/usr/local/etc/freeside/nytprof.out" + #PERL5OPT="-d:NYTProf" freeside-queued $QUEUED_USER echo "done." echo -n "Starting freeside-sqlradius-radacctd: " @@ -44,6 +48,10 @@ case "$1" in echo "done." done + #ip=`/sbin/ifconfig $IF | grep 'inet addr:' | cut -d: -f2- | cut -d' ' -f1` + #cp /opt/rt3/etc/RT_SiteConfig.pm.ORIG /opt/rt3/etc/RT_SiteConfig.pm + #perl -pi -e "s/localhost/$ip/" /opt/rt3/etc/RT_SiteConfig.pm + ;; stop) # Stop daemons. -- cgit v1.2.1 From 6d406c07de8348a0a0e5ec1e8f2a3d8ffe5309cd Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 13 Aug 2009 09:25:02 +0000 Subject: fix reverted changes. grr. RT#4964 --- httemplate/view/cust_main.cgi | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index bbdfe5166..3e5a8cee3 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -113,6 +113,7 @@ Comments % if ( ! $conf->exists('cust_main-disable_notes') || $notecount) { % unless ( $view eq 'notes' && $cust_main->comments !~ /[^\s\n\r]/ ) { +
    Notes
    % } @@ -206,6 +207,10 @@ Comments % } +% if ( $view eq 'change_history' ) { # || $view eq 'jumbo' +<% include('cust_main/change_history.html', $cust_main ) %> +% } + <% include('/elements/footer.html') %> <%init> @@ -243,7 +248,8 @@ $views{'Tickets'} = 'tickets' $views{'Packages'} = 'packages'; $views{'Payment History'} = 'payment_history' unless $conf->config('payby-default' eq 'HIDE'); -#$views{'Change History'} = ''; +$views{'Change History'} = 'change_history' + if $curuser->access_right('View customer history'); $views{'Jumbo'} = 'jumbo'; my %viewname = reverse %views; -- cgit v1.2.1 From 9183ef77c42759ae38c454c649a2ad3e388e261b Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 13 Aug 2009 09:35:48 +0000 Subject: adding autogen changelog on 1.9 --- ChangeLog | 30865 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 30865 insertions(+) create mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..d39277bcc --- /dev/null +++ b/ChangeLog @@ -0,0 +1,30865 @@ +2009-08-13 02:25 ivan + + * httemplate/view/cust_main.cgi: fix reverted changes. grr. + RT#4964 + +2009-08-12 17:26 ivan + + * init.d/freeside-init: useful stuff for webdemo & profiling + +2009-08-12 07:58 jeff + + * bin/billco-upload, Makefile, FS/FS/Conf.pm, FS/FS/Cron/upload.pm, + FS/bin/freeside-daily, FS/bin/freeside-monthly, + httemplate/config/config-view.cgi: internalize billco-upload and + automate the transfer to the provider RT#5902 + +2009-08-12 04:57 ivan + + * httemplate/: docs/about.html, docs/credits.html, + docs/license.html, elements/header-popup.html: slight + about/credits UI tweak + +2009-08-11 22:22 ivan + + * FS/FS/: cust_main.pm, part_event/Action.pm, + part_event/Action/cust_bill_fee_percent.pm, + part_event/Action/fee.pm: add pre-bill event stage for late fees, + RT#5589 + +2009-08-11 19:36 ivan + + * FS/FS/cust_pkg.pm, httemplate/misc/bulk_change_pkg.cgi, + httemplate/search/cust_pkg.cgi: fix multiple pkgpart search, + RT#5924 + +2009-08-11 14:33 rsiddall + + * rpm/freeside.spec: Back out kludge to show CVS snapshot date in + version number in GUI. You can get the snapshot date from the + release number using "rpm -q freeside". + +2009-08-11 14:29 rsiddall + + * Makefile: Reset RPM release number back to 1 on a new version + release. + +2009-08-10 19:45 ivan + + * FS/FS/part_event/Action/writeoff.pm: fix bad debt writeoff + action, RT#5798 + +2009-08-10 19:34 ivan + + * FS/FS/cust_main.pm: add $company_name and $company_address to + decline template, RT#5869 + +2009-08-10 16:04 mark + + * FS/FS/AccessRight.pm, httemplate/edit/cust_main_attach.cgi, + httemplate/edit/process/cust_main_attach.cgi, + httemplate/view/attachment.html, httemplate/view/cust_main.cgi, + httemplate/view/cust_main/attachments.html: Improve handling of + deleted attachments + +2009-08-10 14:44 ivan + + * FS/FS/part_export/netsapiens.pm: last nits on netsapiens export, + RT#5226 + +2009-08-10 11:05 mark + + * FS/FS/part_export/shellcommands_withdomain.pm: Add preset for + magicmail + +2009-08-10 04:57 ivan + + * fs_selfservice/FS-SelfService/cgi/process_svc_external.html: when + using pkg-balances, limit self-service access when a customer + with multiple packages logs on, RT#4189 + +2009-08-10 04:50 ivan + + * FS/FS/ClientAPI/MyAccount.pm, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/cgi/myaccount.html, + fs_selfservice/FS-SelfService/cgi/myaccount_menu.html, + fs_selfservice/FS-SelfService/cgi/selfservice.cgi, + fs_selfservice/FS-SelfService/cgi/login.html, + fs_selfservice/FS-SelfService/cgi/logout.html, + fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html: + when using pkg-balances, limit self-service access when a + customer with multiple packages logs on, RT#4189 + +2009-08-09 16:53 jeff + + * FS/FS/part_event/Action/cust_bill_spool_csv.pm: whoops: theory + should match practice + +2009-08-09 16:45 jeff + + * FS/FS/part_event/Action/cust_bill_spool_csv.pm: fix per agent + spools + +2009-08-09 15:47 jeff + + * FS/FS/cust_bill_pkg.pm: don't bomb when the line item has no + start date + +2009-08-09 02:05 mark + + * FS/FS/cust_attachment.pm, httemplate/edit/cust_main_attach.cgi, + httemplate/edit/process/cust_main_attach.cgi, + httemplate/view/attachment.html, httemplate/view/cust_main.cgi, + httemplate/view/cust_main/attachments.html, FS/FS/AccessRight.pm, + FS/FS/Conf.pm, FS/FS/Mason.pm, FS/FS/Record.pm, FS/FS/Schema.pm: + Add cust_attachment stuff + +2009-08-07 16:08 ivan + + * FS/FS/Conf.pm, httemplate/edit/cust_main.cgi, + httemplate/edit/cust_main/top_misc.html, + httemplate/edit/process/cust_main.cgi, + httemplate/elements/tr-input-date-field.html: add ability to edit + signup dates (turn on cust_main-edit_signupdate config), RT#4644 + +2009-08-06 17:39 ivan + + * FS/FS/cust_main.pm, httemplate/edit/process/quick-cust_pkg.cgi, + httemplate/elements/tr-input-date-field.html, + httemplate/misc/order_pkg.html, + httemplate/view/cust_main/packages.html: don't start recurring + billing when a start date hasn't been reached yet either... and + since that works, add the start date to new package order, + RT#5347 + +2009-08-05 17:41 ivan + + * FS/FS/part_export/netsapiens.pm: pass mac addresses as lower-case + to netsapiens, RT#5226 + +2009-08-05 17:39 ivan + + * FS/FS/svc_phone.pm: delete phone_device records when svc_phone is + deleted, RT#5226 + +2009-08-05 16:32 ivan + + * FS/FS/part_pkg/: agent.pm, base_rate.pm, flat.pm, + flat_delayed.pm, prorate_delayed.pm: fix cancellation errors with + updated flat_introrate, RT#5865 + +2009-08-04 19:27 ivan + + * FS/FS/: svc_acct.pm: export negative byte values to chillispot + attributes as 0, RT#5815 + +2009-08-04 16:43 ivan + + * FS/: FS/svc_acct.pm, bin/freeside-sqlradius-reset: hopefully + ignore errors about deleted accounts and properly finish + freeside-sqlradius-reset, RT#5868 + +2009-08-04 15:04 ivan + + * FS/: FS/svc_Common.pm, bin/freeside-sqlradius-reset: ignore + problams calling ->overlimit during sqlradius-reset, wtf?! + RT#5868 + +2009-08-03 17:19 ivan + + * FS/FS/cust_pkg.pm: don't reset usage on package change when + usage_rollover is on, it adds twice... + +2009-08-03 12:54 ivan + + * httemplate/elements/header.html: looks slightly better in default + IE hopefully + +2009-08-03 07:17 jeff + + * FS/FS/part_export/shellcommands.pm: new doesn't exist + +2009-08-03 07:07 jeff + + * FS/FS/part_export/shellcommands.pm: bad tyops + +2009-08-01 12:16 jeff + + * FS/FS/: Schema.pm, queue.pm, queue_arg.pm: support broader array + of queue args #5855, fallout from #5495 + +2009-07-31 06:20 ivan + + * FS/FS/ClientAPI/MyAccount.pm, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/cgi/ach_payment_results.html, + fs_selfservice/FS-SelfService/cgi/change_bill.html, + fs_selfservice/FS-SelfService/cgi/change_password.html, + fs_selfservice/FS-SelfService/cgi/change_pay.html, + fs_selfservice/FS-SelfService/cgi/change_ship.html, + fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html, + fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html, + fs_selfservice/FS-SelfService/cgi/delete_svc.html, + fs_selfservice/FS-SelfService/cgi/footer.html, + fs_selfservice/FS-SelfService/cgi/header.html, + fs_selfservice/FS-SelfService/cgi/login.html, + fs_selfservice/FS-SelfService/cgi/logout.html, + fs_selfservice/FS-SelfService/cgi/make_ach_payment.html, + fs_selfservice/FS-SelfService/cgi/make_payment.html, + fs_selfservice/FS-SelfService/cgi/myaccount.html, + fs_selfservice/FS-SelfService/cgi/myaccount_menu.html, + fs_selfservice/FS-SelfService/cgi/payment_results.html, + fs_selfservice/FS-SelfService/cgi/process_change_bill.html, + fs_selfservice/FS-SelfService/cgi/process_change_password.html, + fs_selfservice/FS-SelfService/cgi/process_change_pay.html, + fs_selfservice/FS-SelfService/cgi/process_change_pkg.html, + fs_selfservice/FS-SelfService/cgi/process_change_ship.html, + fs_selfservice/FS-SelfService/cgi/process_order_pkg.html, + fs_selfservice/FS-SelfService/cgi/process_order_recharge.html, + fs_selfservice/FS-SelfService/cgi/process_svc_acct.html, + fs_selfservice/FS-SelfService/cgi/provision.html, + fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html, + fs_selfservice/FS-SelfService/cgi/recharge_prepay.html, + fs_selfservice/FS-SelfService/cgi/recharge_results.html, + fs_selfservice/FS-SelfService/cgi/selfservice.cgi, + fs_selfservice/FS-SelfService/cgi/view_invoice.html, + fs_selfservice/FS-SelfService/cgi/view_usage_details.html: skin + up self-service according to config passed from backend, RT#5530 + +2009-07-31 00:58 ivan + + * bin/cdr-transnexus.import: only need Customer-CDRs, RT#5229 + +2009-07-31 00:51 ivan + + * bin/cdr-transnexus.import: only need Customer-CDRs, RT#5229 + +2009-07-30 02:19 ivan + + * FS/FS/: cust_main.pm, ClientAPI/MyAccount.pm: pass a pkgnum from + self-service if applicable, RT#4339 + +2009-07-30 01:43 ivan + + * fs_selfservice/FS-SelfService/cgi/selfservice.cgi: lost fix for + illegal state? + +2009-07-30 00:39 ivan + + * httemplate/view/cust_main/change_history.html: small fix to + change history to not error out with svc_acct services, RT#1005 + +2009-07-30 00:35 mark + + * FS/FS/part_export/shellcommands.pm: Make no_queue option work + correctly + +2009-07-29 23:52 ivan + + * httemplate/view/cust_main/payment_history.html: didn't mean to + leave a Dump(er) there + +2009-07-29 23:50 ivan + + * httemplate/edit/cust_pay.cgi: another accidentally (alliterated) + vestigial variable + +2009-07-29 23:49 ivan + + * httemplate/edit/cust_credit.cgi: don't need to lookup cust_main + here + +2009-07-29 23:48 ivan + + * httemplate/elements/select-cust_pkg-balances.html: fix for + stickiness on errors + +2009-07-29 23:42 ivan + + * FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/cust_bill.pm, + FS/FS/cust_bill_ApplicationCommon.pm, FS/FS/cust_bill_pay.pm, + FS/FS/cust_credit.pm, FS/FS/cust_credit_bill.pm, + FS/FS/cust_pay.pm, FS/FS/cust_pay_pending.pm, + FS/FS/cust_pay_void.pm, FS/FS/cust_pkg.pm, FS/FS/cust_main.pm, + httemplate/edit/cust_credit.cgi, httemplate/edit/cust_pay.cgi, + httemplate/edit/process/cust_pay.cgi, + httemplate/elements/select-cust_pkg-balances.html, + httemplate/elements/tr-select-cust_pkg-balances.html, + httemplate/view/cust_bill.cgi, httemplate/view/cust_pay.html, + httemplate/view/cust_main/packages.html, + httemplate/view/cust_main/payment_history.html, + httemplate/view/cust_main/packages/status.html, + httemplate/view/cust_main/payment_history/payment.html, + httemplate/view/cust_main/payment_history/credit.html, + httemplate/view/cust_main/payment_history/voided_payment.html: + experimental package balances, RT#4339 + +2009-07-28 15:21 jeff + + * FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/cust_bill.pm, + FS/FS/cust_main.pm, httemplate/edit/cust_main/billing.html, + httemplate/view/cust_main/billing.html: feature to email CSV of + CDRs with invoices #5727 + +2009-07-28 14:17 ivan + + * FS/FS/Conf.pm, FS/FS/AccessRight.pm, FS/FS/Mason.pm, + FS/FS/svc_external.pm, httemplate/pref/pref.html, + httemplate/view/cust_main.cgi, + httemplate/view/cust_main/change_history.html: adding a basic + change history using history tables, RT#1005, RT#4357 + +2009-07-27 19:12 mark + + * FS/FS/part_export/: shellcommands.pm, + shellcommands_withdomain.pm: Add no_queue option to shellcommands + exports + +2009-07-27 12:51 ivan + + * httemplate/misc/cancel_pkg.html: fix spacing + +2009-07-27 02:59 ivan + + * httemplate/search/: report_cust_pay.html, + elements/cust_pay_or_refund.html: searching for voided payments + by void date as well, RT#5786 + +2009-07-27 02:07 ivan + + * httemplate/: elements/menu.html, search/cust_pay_void.html, + search/report_cust_pay.html, + search/elements/cust_pay_or_refund.html, view/cust_pay.html, + view/cust_pay_void.html: voided payment report, RT#5786 + +2009-07-26 23:17 ivan + + * FS/FS/Conf.pm, httemplate/config/config-view.cgi: add deprecated + config options back to Conf.pm to fix "unapplypayments" fails + existential comparison errors, RT#2927 + +2009-07-26 20:26 jeff + + * FS/FS/Conf.pm, FS/FS/cust_main.pm, FS/FS/cust_pkg.pm, + httemplate/edit/cust_main.cgi, + httemplate/edit/cust_main/bottomfixup.js, + httemplate/edit/cust_main/contact.html, + httemplate/elements/location.html, + httemplate/misc/xmlhttp-cust_main-censustract.html, + httemplate/search/cust_pkg.cgi, + httemplate/view/cust_main/misc.html: FCC from 477 improvements + #4912 + +2009-07-26 13:23 jeff + + * httemplate/search/svc_broadband.cgi: fix links + +2009-07-26 12:36 ivan + + * rt/: FREESIDE_MODIFIED, html/Elements/PageLayout, + html/Elements/SelectDate: fix the date picker in RT to use + jscalendar instead of an HTML popup (that had acquired the page + header, eek), RT#1682 + +2009-07-26 11:40 ivan + + * FS/FS/Conf_compat17.pm: bring up-to-date wrt 1.7 Conf.pm + 1.180.2.49 (2009-7-26), RT#2873 + +2009-07-25 23:38 jeff + + * FS/bin/freeside-apply_payments_and_credits: command line tool to + apply payments and credits + +2009-07-25 15:00 ivan + + * htetc/handler.pl: set a character encoding for all pages; this + should fix problems with diamond question marks even when the + server gets an UTF-8 default setting, RT#3094 + +2009-07-25 14:33 ivan + + * FS/FS/cust_event.pm, httemplate/search/cust_event.html: this + should fix the re-email/print links on event search pages sending + too much, RT#5740, RT#5570 + +2009-07-25 00:57 ivan + + * FS/FS/Record.pm: teach Record.pm about BYTEA handling in order to + store files in the db, RT#4964 + +2009-07-24 02:38 ivan + + * FS/FS/: Conf.pm, svc_acct.pm: add handling of ChilliSpot (and + CoovaChilli) Max attributes, specifically + ChilliSpot-Max-{Input,Output,Total}-{Octets,Gigawords}, RT#5815 + +2009-07-23 22:51 mark + + * FS/bin/freeside-void-payments: Add -v switch (verbose) to + freeside-void-payments + +2009-07-23 12:46 ivan + + * FS/FS/cust_pay.pm: avoid harmless warning: Use of uninitialized + value in string ne + +2009-07-23 12:40 ivan + + * FS/bin/freeside-void-payments: fix -r option, RT#5675 + +2009-07-23 09:48 jeff + + * httemplate/browse/svc_acct_pop.cgi: restore svc_acct_pop editing + +2009-07-23 06:25 ivan + + * httemplate/: browse/cust_main_county.cgi, + edit/process/cust_main_county-collapse.cgi: add back remove + ("collapse") links again. on each line this time. RT#2973 + +2009-07-22 23:58 ivan + + * FS/FS/Tron.pm: need to see who is still on deb 4 & pg 7.4 + +2009-07-22 15:05 ivan + + * httemplate/view/cust_main/misc.html: fix bombing out on new + DateTime + +2009-07-21 11:44 ivan + + * FS/FS/: Schema.pm, part_pkg/cdr_termination.pm: sub-penny + termination pricing too, RT#5495 + +2009-07-21 00:03 ivan + + * FS/FS/part_pkg/voip_cdr.pm: yow. fix spurious charge errors + w/single_price, round to four decimal places (wtf?) instead of 2, + RT#5495 + +2009-07-20 22:29 ivan + + * FS/FS/part_pkg/voip_cdr.pm: and fix min_charge option, RT#5495 + +2009-07-20 22:27 ivan + + * FS/FS/part_pkg/voip_cdr.pm: if we're going to do recur_Common, + have to use and @ISA (and capitalize) it + +2009-07-20 17:20 ivan + + * FS/FS/part_pkg/voip_cdr.pm: don't have a money type in package + definitions at the moment + +2009-07-20 16:01 jeff + + * FS/FS/: Conf.pm, cust_bill.pm: config setting to have emailed + invoices include call details #5275 + +2009-07-20 07:26 jeff + + * httemplate/elements/checkbox.html, + httemplate/elements/tr-checkbox.html, + httemplate/elements/tr-justtitle.html, + httemplate/elements/tr-title.html, FS/FS/Schema.pm, + FS/FS/cust_bill.pm, FS/FS/cust_bill_pkg.pm, FS/FS/cust_main.pm, + FS/FS/part_pkg.pm, FS/FS/part_pkg_link.pm, + httemplate/edit/part_pkg.cgi, httemplate/edit/elements/edit.html, + httemplate/edit/process/part_pkg.cgi: bundle bill linked packages + into top line total when desired #5724 + +2009-07-19 21:51 ivan + + * FS/FS/cust_pkg.pm: one $conf is enough + +2009-07-19 21:40 ivan + + * rt/: FREESIDE_MODIFIED, lib/RT/Transaction_Overlay.pm: slightly + improve terrible quoting behavior when you change MessageBoxWidth + +2009-07-19 21:19 ivan + + * httemplate/elements/header.html: fix preferences links showing as + blue/purple on RT side + +2009-07-19 21:14 ivan + + * rt/: FREESIDE_MODIFIED, html/Ticket/Create.html: fix badly styled + links on ticket create (fallout from RT borging/styling) + +2009-07-17 16:33 ivan + + * FS/FS/cdr.pm: remove unused cdr_upstream_rate + +2009-07-17 16:10 rsiddall + + * rpm/freeside.spec: Filter out requirements for specific Freeside + modules so that you can install an RPM which requires missing + Freeside modules. + +2009-07-17 15:26 ivan + + * FS/: FS/cust_main.pm, FS/Cron/bill.pm, bin/freeside-daily: commit + pkgpart exclusion for billing run, RT#5495 + +2009-07-17 07:58 jeff + + * bin/billco-upload: add mutex and commit changes found on + installed system + +2009-07-16 19:29 jeff + + * httemplate/search/cust_pkg.cgi: FSM, another missed file for 477 + reporting + +2009-07-16 18:44 jeff + + * FS/FS/: Conf.pm, cust_main.pm, cust_pkg.pm, part_pkg/voip_cdr.pm: + bill usage when cancelling package + +2009-07-16 18:08 jeff + + * bin/generate-table-module: black magic to edit Mason.pm as well + +2009-07-16 17:35 ivan + + * FS/FS/part_pkg/: voip_cdr.pm: add single_price option so you can + do one per-minute price without rate tables, RT#5495 + +2009-07-16 17:33 ivan + + * FS/MANIFEST: get rid of cdr_upstream_rate table and some other + old convergent cruft + +2009-07-16 17:10 ivan + + * FS/: FS/Schema.pm, FS/cdr.pm, FS/cdr_upstream_rate.pm, + FS/part_pkg/voip_cdr.pm, FS.pm, t/cdr_upstream_rate.t: get rid of + cdr_upstream_rate table and some other old convergent cruft + +2009-07-16 15:16 jeff + + * FS/FS/Mason.pm: dark magic coming soon + +2009-07-15 18:57 jeff + + * httemplate/search/477.html: duh! more 477 files + +2009-07-15 18:35 jeff + + * httemplate/search/report_477.html: missed file for 477 reporting + +2009-07-15 16:06 ivan + + * FS/FS/part_pkg/cdr_termination.pm: unused for now + +2009-07-15 15:49 ivan + + * FS/FS/: Conf.pm, cdr.pm: add option to trim leading zeros when + setting charged_party to accountcode, RT#5495 + +2009-07-14 12:06 rsiddall + + * FS/FS/part_export/domreg_net_dri.pm: Minor bug fix, spotted by + Jeff. + +2009-07-14 12:05 rsiddall + + * FS/FS/svc_domain.pm: Changed description of "action" field to + match domain registration exports. + +2009-07-13 20:14 ivan + + * htetc/handler.pl: fix warnings, from RT merge fallout + +2009-07-13 19:53 ivan + + * FS/FS/part_export/netsapiens.pm: fix netsapiens device + provisioning? or at least better debugging, RT#5226 + +2009-07-13 19:52 ivan + + * httemplate/elements/tr-select-did.html: stop Dumper spew + +2009-07-13 17:28 rsiddall + + * Makefile, FS/FS/svc_domain.pm, + FS/FS/part_export/domreg_net_dri.pm, + httemplate/edit/process/domreg.cgi: New export to + register/transfer/renew/revoke domains using Net::DRI. Currently + optimized for OpenSRS. Should become more generalized in later + releases. Modified Makefile to insert the Freeside log folder + into the new export. Modified svc_domain.pm to prevent + generation of transfer requests when a domain is moved to a + different package with a domain registration attached to one of + the included services. Modified domreg.cgi to display errors on + a separate page. + +2009-07-13 09:02 jeff + + * FS/FS/: tax_rate.pm, tax_rate_location.pm: correct ordering and + other bugs in tax updates + +2009-07-13 03:12 ivan + + * FS/FS/part_pkg/recur_Common.pm: eliminate harmless "no %info hash + found in FS::part_pkg::recur_Common, skipping" warning + +2009-07-13 02:19 ivan + + * FS/FS/ClientAPI/MyAccount.pm, + fs_selfservice/FS-SelfService/cgi/cust_bill-logo.cgi: fix + self-service agent-specific logos + +2009-07-13 02:10 ivan + + * httemplate/view/cust_bill-logo.cgi: fix old-style agent-virt + logo? + +2009-07-13 00:21 ivan + + * conf/invoice_html: thank you IE8 + +2009-07-13 00:10 ivan + + * httemplate/search/report_unapplied_cust_pay.html: clarify wording + +2009-07-12 20:24 ivan + + * rt/html/Elements/PageLayout: think that should be it, fix bar + when there's no primary $page_tabs + +2009-07-12 20:15 ivan + + * rt/html/Elements/Footer: no need for Time to display either + +2009-07-12 19:33 ivan + + * rt/html/Elements/PageLayout: style RT's menubars like ours + +2009-07-12 18:50 ivan + + * httemplate/elements/: header.html, menubar.html: style nits + +2009-07-12 16:45 ivan + + * httemplate/elements/header.html: fix header sizes :/ + +2009-07-12 16:38 ivan + + * FS/FS/CGI.pm: this should fix $fsurl under the unified RT? sure + hope so + +2009-07-12 16:27 ivan + + * rt/html/NoAuth/css/3.5-default/titlebox.css: fix excessive RT + margins + +2009-07-12 16:25 ivan + + * httemplate/edit/cust_main.cgi: ACL on customer edit + +2009-07-12 16:22 ivan + + * httemplate/elements/header.html, httemplate/elements/menu.html, + httemplate/elements/xmenu.css, httemplate/elements/xmenu.top.css, + rt/FREESIDE_MODIFIED, rt/etc/RT_SiteConfig.pm, + rt/html/Elements/Header, + rt/html/NoAuth/css/3.5-default/freeside.css, + rt/html/NoAuth/css/3.5-default/misc.css, + rt/html/Ticket/Display.html: resolve style weirdness (fallout + from RT integration), especially non-fixed-width comment boxes, + menu/searchbar differences, RT#1169 + +2009-07-12 12:32 ivan + + * httemplate/elements/menu.html: update tickting config + descriptions + +2009-07-12 06:27 jeff + + * FS/FS/Record.pm: stop gratuitous hash manipulatoin during enum + untaint + +2009-07-10 19:40 ivan + + * bin/drop_slony.slonik: notes + +2009-07-10 10:50 ivan + + * httemplate/elements/: select-did.html, tr-select-did.html: fix + svc_phone provisioning! + +2009-07-09 17:36 ivan + + * FS/FS/cdr.pm: fix sansay CDR import to ignore "NA" in dates, + RT#5495 + +2009-07-09 16:59 ivan + + * FS/FS/cdr.pm, FS/FS/cdr/sansay.pm, eg/cdr_template.pm: sansay + CDRs, RT#5495 + +2009-07-09 16:58 ivan + + * FS/bin/freeside-cdr-sftp_and_import: add -r option + +2009-07-09 14:05 ivan + + * FS/FS/cust_main.pm, httemplate/elements/menu.html, + httemplate/search/report_unapplied_cust_pay.html, + httemplate/search/unapplied_cust_pay.html: unapplied payments + report, RT#4861 + +2009-07-09 13:36 ivan + + * httemplate/search/elements/cust_main_dayranges.html: no idea how + i missed fixing this before + +2009-07-09 13:18 ivan + + * httemplate/search/report_receivables.cgi: oops + +2009-07-08 19:34 ivan + + * rt/html/Elements/Header: doh, fix RT onLoadHook; this fixes + "Undefined subroutine &HTML::Mason::Commands::onLoadHook" error + on ticket creation and otherwise, RT#1169 + +2009-07-08 04:12 ivan + + * FS/FS/TicketSystem/RT_External.pm, + FS/FS/TicketSystem/RT_Internal.pm, httemplate/elements/menu.html, + FS/FS/Conf.pm, FS/FS/Mason.pm, htetc/handler.pl, + httemplate/elements/about_freeside.html, + httemplate/elements/about_rt.html, + httemplate/elements/header.html, + httemplate/elements/popup_link.html, rt/FREESIDE_MODIFIED, + rt/html/Elements/Header, rt/html/Elements/PageLayout, + rt/html/Elements/Tabs, rt/html/Prefs/SearchOptions.html, + rt/html/User/Prefs.html: borg RT menus, RT#1169 + +2009-07-07 20:33 ivan + + * httemplate/search/: report_receivables.cgi, + report_unapplied_cust_pay.html, unapplied_cust_pay.html, + elements/cust_main_dayranges.html: factor out the range-handling + portions of receivables report, start on a similar unapplied + payment report, RT#4861 + +2009-07-07 02:53 ivan + + * FS/FS/Schema.pm, httemplate/view/svc_broadband.cgi: allow null + svc_broadband.ip_addr + +2009-07-07 02:23 ivan + + * FS/FS/: Conf.pm, Schema.pm, svc_broadband.pm: allow null + svc_broadband.ip_addr + +2009-07-07 02:22 ivan + + * httemplate/edit/svc_broadband.cgi: UI nit - double # + +2009-07-07 00:32 mark + + * FS/bin/freeside-void-payments: Add freeside-void-payments script + for returned check processing + +2009-07-06 17:53 ivan + + * FS/FS/cdr/netcentrex.pm: for netcentrex CDRs, import duration to + duration field (previously only billsec) + +2009-07-06 17:47 ivan + + * FS/FS/cdr.pm: on CDR date parse, consider 1970-01-01 NULL like + 1900-01-01, RT#4081 + +2009-07-06 16:14 ivan + + * httemplate/search/: cdr.html, report_cdr.html: search cdr by + acctid + +2009-07-06 14:34 ivan + + * httemplate/browse/rate_region.html: align, display countrycode + with +, space between prefixes allowing wrapping + +2009-07-05 17:28 ivan + + * httemplate/view/svc_phone.cgi: fix incoming CDR links wrt + cdrbatch field + +2009-07-05 17:10 ivan + + * httemplate/elements/: select-did.html, tr-select-did.html: doh + +2009-07-05 16:56 ivan + + * httemplate/elements/: select-did.html, tr-select-did.html: allow + svc_phone.phonenum to be edited when a DID selector is not in use + +2009-07-05 16:17 ivan + + * httemplate/search/cdr.html: format start/answer/end dates and + link svcnum to service + +2009-07-05 14:35 ivan + + * FS/FS/Schema.pm, FS/FS/cdr.pm, + httemplate/elements/checkboxes.html, httemplate/search/cdr.html, + httemplate/search/report_cdr.html: CDR search by dcontext, + charged_party, toggle of display fields, RT#4081 + +2009-07-03 17:47 ivan + + * FS/FS/part_event/Condition/: cust_payments.pm, + cust_payments_pkg.pm: add condition based on total customer + payments as a multiplier of a specific package, RT#3983 + +2009-07-03 17:08 ivan + + * FS/FS/part_event/Condition/once.pm: spealing + +2009-07-02 04:22 ivan + + * FS/FS/cdr.pm, FS/FS/Schema.pm, FS/FS/cdr_termination.pm, + FS/FS/part_pkg/cdr_termination.pm, + httemplate/edit/cust_main/billing.html, + httemplate/search/cdr.html, httemplate/search/report_cdr.html: + settlement cdr processing, RT#5495 + +2009-07-01 19:02 ivan + + * FS/FS/: cust_main.pm, part_event/Action/cust_bill_fee_percent.pm, + part_event/Action/fee.pm: fix late fees, RT#5665 + +2009-07-01 18:26 jeff + + * FS/FS/ClientAPI/MyAccount.pm, FS/FS/part_pkg/flat.pm, + FS/FS/part_pkg/flat_introrate.pm, httemplate/search/cust_pkg.cgi: + update flat_introrate plan to better fit current codebase RT#4912 + +2009-07-01 03:28 ivan + + * FS/MANIFEST, FS/FS/Schema.pm, FS/FS/cdr_termination.pm, + FS/FS/cust_main.pm, FS/FS/part_pkg/cdr_termination.pm, + FS/FS/part_pkg/recur_Common.pm, FS/t/cdr_termination.t, + httemplate/edit/cust_main/billing.html, + httemplate/view/cust_main/billing.html: start of settlement CDR + processing, RT#5495 + +2009-06-30 22:34 ivan + + * FS/FS/part_event/Action/cust_bill_fee_percent.pm, + FS/FS/part_event/Action/fee.pm, + httemplate/elements/select-taxclass.html, + httemplate/elements/tr-select-taxclass.html: add tax class + selection back for late charges w/1.9 events, RT#5665 + +2009-06-30 13:18 jeff + + * FS/FS.pm, httemplate/elements/menu.html: documentation + corrections + +2009-06-30 12:38 ivan + + * FS/FS/Schema.pm, FS/FS/part_pkg_taxclass.pm, + httemplate/browse/part_pkg_taxclass.html, + httemplate/edit/part_pkg_taxclass.html, + httemplate/edit/process/part_pkg_taxclass.html, + httemplate/elements/menu.html, + httemplate/elements/select-taxclass.html, + httemplate/elements/tr-select-taxclass.html: disabling a + taxclass, RT#5472 + +2009-06-30 05:32 ivan + + * httemplate/edit/quick-charge.html: remove debugging + +2009-06-30 05:28 ivan + + * FS/FS/Schema.pm, FS/FS/cust_main.pm, FS/FS/cust_pkg.pm, + httemplate/edit/REAL_cust_pkg.cgi, + httemplate/edit/quick-charge.html, + httemplate/edit/process/REAL_cust_pkg.cgi, + httemplate/view/cust_main/packages/status.html, + FS/FS/Cron/bill.pm, httemplate/edit/process/quick-charge.cgi: + one-time charge "hold for later" / any package future start date, + RT#5347 + +2009-06-30 04:09 ivan + + * FS/FS/part_export/netsapiens.pm: this will help + +2009-06-30 02:38 ivan + + * FS/FS/: phone_device.pm, part_export/netsapiens.pm: more steps to + netsapiens export, RT#5226 + +2009-06-29 19:54 ivan + + * FS/FS/part_export/netsapiens.pm: add DID association w/user? + docs from netsapiens rough... RT#5226 + +2009-06-29 18:42 ivan + + * FS/FS.pm, FS/MANIFEST, FS/FS/Mason.pm, FS/FS/Schema.pm, + FS/FS/part_device.pm, FS/FS/phone_device.pm, FS/FS/svc_phone.pm, + FS/t/part_device.t, FS/t/phone_device.t, + httemplate/browse/part_device.html, + httemplate/edit/part_device.html, + httemplate/edit/phone_device.html, + httemplate/edit/process/part_device.html, + httemplate/edit/process/phone_device.html, + httemplate/misc/delete-phone_device.html, + httemplate/misc/part_device-import.html, + httemplate/elements/menu.html, + httemplate/misc/process/part_device-import.html, + httemplate/view/svc_phone.cgi: phone devices (for netsapiens + integration), RT#5226 + +2009-06-29 15:48 rsiddall + + * rpm/freeside.spec: Fix PDF invoice generation, including + requirement for ghostscript. + +2009-06-29 07:45 jeff + + * bin/cust_pay_histogram: show total number of payments + +2009-06-29 06:55 jeff + + * bin/cust_pay_histogram: commandline tool for examining cust_pay + records by date range #5652 + +2009-06-29 06:53 jeff + + * FS/FS/part_pkg_report_option.pm, FS/FS/Conf.pm, FS/FS/Schema.pm, + FS/FS/cust_main.pm, FS/FS/cust_pkg.pm, + FS/t/part_pkg_report_option.t, FS/FS.pm, FS/MANIFEST, + httemplate/browse/part_pkg_report_option.html, + httemplate/edit/part_pkg.cgi, + httemplate/edit/part_pkg_report_option.html, + httemplate/edit/cust_main/bottomfixup.html, + httemplate/edit/cust_main/bottomfixup.js, + httemplate/edit/cust_main/choose_tax_location.html, + httemplate/edit/process/part_pkg.cgi, + httemplate/edit/process/part_pkg_report_option.html, + httemplate/misc/xmlhttp-cust_main-censustract.html, + httemplate/edit/cust_main/contact.html, + httemplate/elements/location.html, httemplate/elements/menu.html, + httemplate/search/cust_main.html, + httemplate/search/report_cust_main.html, + httemplate/search/report_cust_pkg.html: FCC form 477 reporting + #4912 + +2009-06-28 23:21 ivan + + * FS/MANIFEST: remove freeside-expiration-alerter + +2009-06-26 17:55 ivan + + * FS/bin/freeside-expiration-alerter: replaced by + FS::Cron::alert_expiration + +2009-06-26 16:21 ivan + + * FS/bin/freeside-queued: doh, brainfart, RT#5572 + +2009-06-26 16:12 ivan + + * FS/bin/freeside-queued: add -s and -n flags to freeside-daily to + specify the kinds of jobs to be run, RT#5572 + +2009-06-26 11:53 ivan + + * FS/FS/cust_main.pm: in smart_search, move duplicate elimination + bits so that they're used even when doing an exact search on a + browser-remembered result + +2009-06-25 23:55 mark + + * FS/: FS/Conf.pm, bin/freeside-daily: Add expiration alerts to + freeside-daily routine + +2009-06-25 13:23 ivan + + * FS/FS/ClientAPI/Signup.pm: finish fixing "Real time processing + not enabled!" error when using signup without any real-time + processor + +2009-06-25 12:55 ivan + + * FS/FS/ClientAPI/Signup.pm: eliminate harmless warning log spam: + Argument "" isn't numeric in numeric eq (==) at + /usr/local/share/perl/5.8.8/FS/ClientAPI/Signup.pm line 57 + +2009-06-25 12:47 ivan + + * FS/FS/: agent.pm, ClientAPI/Signup.pm: fix signups for the + no-gateway-at-all case, RT#5673 + +2009-06-25 12:06 ivan + + * httemplate/search/cust_tax_adjustment.html: fix tax adjustment + report + +2009-06-24 18:28 ivan + + * FS/FS.pm, FS/MANIFEST, FS/FS/AccessRight.pm, FS/FS/Conf.pm, + FS/FS/Schema.pm, FS/FS/cust_bill.pm, FS/FS/cust_bill_pkg.pm, + FS/FS/cust_main.pm, FS/FS/cust_tax_adjustment.pm, + FS/t/cust_tax_adjustment.t, + httemplate/edit/cust_tax_adjustment.html, + httemplate/edit/process/cust_tax_adjustment.html, + httemplate/search/cust_tax_adjustment.html, + httemplate/view/cust_main/payment_history.html: tax adjustments, + RT#5595 + +2009-06-24 18:22 ivan + + * httemplate/view/cust_main/one_time_charge_link.html: fix extra + whitespace in IE + +2009-06-24 11:36 ivan + + * init.d/freeside-init, FS/bin/freeside-queued: add support for db + profiling, RT#5662 + +2009-06-24 02:07 mark + + * FS/: FS/Cron/alert_expiration.pm, bin/freeside-daily: Move + expiration alerts into FS::Cron::alert_expiration + +2009-06-23 21:42 ivan + + * FS/FS/part_pkg.pm: fix upgrade issue w/ black part_pkg.comment, + RT#3988 + +2009-06-23 18:40 ivan + + * httemplate/graph/cust_bill_pkg.cgi: fix total links on + agent-specific sales report, RT#5449 + +2009-06-23 13:33 rsiddall + + * httemplate/view/svc_domain.cgi: Remove ability to renew domain + registration for more than one year as we can't automatically + bill for multi-year renewals at this time. + +2009-06-22 16:42 ivan + + * FS/FS/cust_pay.pm: fix using encryption produces non-decrypted + data in payment receipts, RT#5536 + +2009-06-22 15:55 ivan + + * FS/FS/Mason.pm, httemplate/search/cust_main.html: fix advanced + customer report failure, RT#5515 + +2009-06-22 10:00 jeff + + * FS/FS/cust_main.pm: wtf? the tax applies but it doesn't? RT#5574 + +2009-06-22 03:45 ivan + + * FS/FS/part_pkg.pm: eliminate harmless upgrade error: Argument "" + isn't numeric in numeric eq (==) at + /usr/local/share/perl/5.8.8/FS/part_pkg.pm line 371. + +2009-06-22 03:39 ivan + + * FS/FS/access_user.pm: fix pod + +2009-06-22 03:28 ivan + + * FS/FS/part_pkg.pm: fix setup/recur -> setup_fee/recur_fee upgrade + +2009-06-22 03:06 ivan + + * FS/FS/Conf.pm, FS/FS/cust_main.pm, + httemplate/search/cust_bill_pkg.cgi, + httemplate/search/report_tax.cgi: finish basic implemention of + tax exemption by tax name hack, RT#5127 + +2009-06-22 00:50 ivan + + * FS/FS.pm, FS/MANIFEST, FS/FS/Conf.pm, FS/FS/Schema.pm, + FS/FS/cust_main.pm, FS/FS/cust_main_exemption.pm, + FS/t/cust_main_exemption.t, + httemplate/edit/cust_main/billing.html, + httemplate/edit/process/cust_main.cgi, + httemplate/view/cust_main/billing.html: tax exemption by tax + name, RT#5127 + +2009-06-21 15:00 ivan + + * FS/FS/part_pkg/agent.pm: eliminate leaky debugging and a warning + about it + +2009-06-21 08:42 jeff + + * FS/FS/part_export/: www_plesk.pm, acct_plesk.pm: link to docs + #5855 + +2009-06-21 08:21 jeff + + * FS/FS/Schema.pm, FS/FS/cust_pkg.pm, FS/FS/part_pkg.pm, + httemplate/browse/agent_type.cgi, httemplate/browse/part_pkg.cgi, + httemplate/edit/REAL_cust_pkg.cgi, + httemplate/edit/agent_type.cgi, httemplate/edit/cust_pkg.cgi, + httemplate/edit/part_bill_event.cgi, + httemplate/edit/part_pkg.cgi, httemplate/edit/reg_code.cgi, + httemplate/edit/cust_main/first_pkg/select-part_pkg.html, + httemplate/misc/bulk_change_pkg.cgi, + httemplate/misc/cancel_pkg.html, + httemplate/misc/cust_main-import.cgi, + httemplate/misc/delay_susp_pkg.html, + httemplate/misc/meta-import.cgi, httemplate/search/cust_main.cgi, + httemplate/search/cust_pkg.cgi, httemplate/search/reg_code.html, + httemplate/search/report_cust_pkg.html, + httemplate/view/cust_main/packages/package.html, + httemplate/view/cust_main/packages/status.html: CUSTOM + packages/actual flag for custom packages #3988 + +2009-06-19 14:49 jeff + + * FS/FS/: cust_bill_pkg_detail.pm, tax_rate.pm: support some older + Pg when upgrading tax rates and cust_bill_pkg_details + +2009-06-19 10:53 jeff + + * fs_selfservice/FS-SelfService/cgi/verify.cgi: treat webpay type + payments as manual + +2009-06-19 05:08 ivan + + * FS/FS/part_pkg/agent.pm: fix the prorating for the package's + first month (whew!) add an option not to prorate the accounts + themselves + +2009-06-19 00:46 ivan + + * FS/FS/cust_main.pm: AND helps alot, RT#5572 for real + +2009-06-19 00:14 ivan + + * FS/FS/cust_main.pm: attempt to optimize the easy parts of billing + run, RT#18737 + +2009-06-18 04:09 ivan + + * FS/FS/part_pkg/agent.pm: omit listing spurious customer details + +2009-06-18 04:07 ivan + + * FS/FS/part_pkg/bulk.pm: bulk price plan fix - don't omit setup + fee + +2009-06-18 04:04 ivan + + * FS/FS/part_pkg/agent.pm: add agent wholsale price plan, RT#4696 + +2009-06-18 04:03 ivan + + * FS/FS/Schema.pm, FS/FS/part_pkg.pm, httemplate/edit/part_pkg.cgi: + add basic part_pkg cost columns for agent wholsale price plan, + RT#4696 + +2009-06-18 03:07 ivan + + * FS/FS/cust_main.pm: uuh, don't bomb out if there *isn't* a postal + fee package + +2009-06-18 02:52 ivan + + * httemplate/images/gray-black-side.png: forgot this + +2009-06-17 18:17 mark + + * httemplate/: elements/menu.html, search/report_receivables.cgi, + search/report_receivables.html: Fix receivables report ACL checks + and menu + +2009-06-16 23:43 mark + + * FS/FS/AccessRight.pm, httemplate/elements/menu.html, + httemplate/search/report_receivables.cgi, + httemplate/search/report_receivables.html: Added separate access + right for receivables report + +2009-06-16 19:39 ivan + + * FS/FS/Conf.pm, FS/FS/access_user.pm, + httemplate/edit/process/REAL_cust_pkg.cgi, + httemplate/edit/process/part_pkg.cgi, + httemplate/edit/process/quick-cust_pkg.cgi, + httemplate/elements/menubar.html, + httemplate/misc/process/link.cgi, httemplate/pref/pref.html, + httemplate/search/cust_event.html, + httemplate/search/cust_main.cgi, httemplate/search/cust_pkg.cgi, + httemplate/view/cust_main.cgi: finish up initial work on customer + view tabs (ensure links back to customer view call include + show=packages if default view isn't jumbo or packages already), + RT#5586 + +2009-06-15 20:29 ivan + + * httemplate/: elements/menubar.html, pref/pref-process.html, + pref/pref.html, view/cust_main.cgi, view/cust_main/packages.html, + view/cust_main/payment_history.html, view/cust_main/tickets.html: + basic customer view tabs, RT#5586 + +2009-06-15 14:41 rsiddall + + * FS/FS/AccessRight.pm, httemplate/view/svc_domain.cgi: Add a new + access right for managing domain registration (registering, + transferring, revoking, renewing, etc.). + +2009-06-15 13:43 jeff + + * FS/FS/cust_main.pm: check for need for postal fee before charging + the customer, not after + +2009-06-15 12:41 rsiddall + + * FS/FS/part_export/domreg_opensrs.pm, + httemplate/edit/process/domreg.cgi, + httemplate/view/svc_domain.cgi: Add domain registration + operations to the View Domain screen, if the domain has an + associated export supporting registration. Shows the domain + status and allows registration, transfer, revocation, or renewal. + Revocation almost never works since the registries impose very + short windows after initial registration. Also updated the + OpenSRS registration export to support the additional operations. + +2009-06-12 20:13 rsiddall + + * rpm/freeside.spec: Default configuration files had + directory-style permission values. + +2009-06-11 19:48 rsiddall + + * rpm/freeside.spec: Freeside no longer uses a datasource-specific + configuration folder. Configuration is kept in the RDBMS and + initialized from the default_conf folder. RT 5579. + +2009-06-10 16:30 jeff + + * conf/invoice_latex: prevent notes from bleeding onto coupon + RT#5537 + +2009-06-10 14:58 ivan + + * FS/FS/: cust_bill.pm, cust_bill_pkg.pm: should hopefully fix old + services showing up on invoices, RT#5451/RT#5514/RT#5564/RT#3032 + +2009-06-10 12:50 ivan + + * FS/FS/Cron/bill.pm: don't add another queued_bill job to the + queue if there's already one waiting to run for a customer, + RT#5572 + +2009-06-10 00:58 ivan + + * httemplate/search/cust_pkg.cgi: this should add the info s1 was + looking for, RT#5539 + +2009-06-09 20:06 ivan + + * FS/bin/freeside-upgrade: doh, semicolon + +2009-06-09 20:00 ivan + + * FS/bin/freeside-upgrade: don't attempt to create h_queue indices, + for SG upgradability + +2009-06-09 19:08 ivan + + * httemplate/edit/payment_gateway.html: update gateway list in + order to add WesternACH, RT#5409 + +2009-06-09 17:02 ivan + + * FS/FS/cust_main.pm: eliminate harmless + + Argument "" isn't numeric in numeric comparison (<=>) at + /usr/local/share/perl/5.8.8/FS/cust_main.pm line 6759. + + warning, sort batched payments on a column that actually exists + +2009-06-04 07:27 ivan + + * httemplate/docs/credits.html: fix scrolling + +2009-06-04 07:09 ivan + + * rpm/freeside.spec: there are lots of contributors too! + +2009-06-04 07:08 ivan + + * httemplate/docs/credits.html: $core->add("jeremyd"); + +2009-06-03 20:49 ivan + + * bin/freeside-migrate-events: much more efficient event migration: + let the database do the work, RT#5426 + +2009-06-03 17:49 ivan + + * bin/freeside-migrate-events: add a -m mode to improve performance + so upgrade can complete for large databases, RT#5426 + +2009-06-03 14:09 rsiddall + + * rpm/freeside.spec: Incorrect permissions on the default + configuration folder caused installation to fail with an + incomplete database initialization. Failure to remove the + ticket_system file from the default configuration folder caused + Freeside to try to use RT. + +2009-06-03 12:52 ivan + + * FS/FS/UID.pm: add a hack to set default schema, cf. + http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration:PostgreSQL_Schema + +2009-05-31 22:43 jeff + + * FS/FS/part_pkg_taxproduct.pm, FS/FS/tax_rate.pm, + httemplate/misc/tax-fetch_and_replace.cgi, + httemplate/misc/process/tax-fetch_and_replace.cgi: a 'start over' + function for the taxproduct based tax data loading + +2009-05-31 02:57 ivan + + * FS/FS/cust_bill.pm: wtf + +2009-05-31 02:45 ivan + + * FS/FS/cust_bill.pm: don't fallback to 'Payable upon receipt' + invoice terms anymore. or in other words, honor setting + 'invoice_default_terms' blank, like in 1.7. RT#5415 + +2009-05-31 01:39 ivan + + * httemplate/browse/part_pkg.cgi: add "hide one-time charges" + toggle, RT#5255 + +2009-05-30 23:59 ivan + + * httemplate/: browse/part_pkg.cgi, elements/select-table.html: + package definition browse/search, filter by package class, + RT#5255 + +2009-05-30 22:15 ivan + + * bin/cdr-netsapiens.import: start of netsapeins cdr import, will + finish up when can connect again, RT#5226 + +2009-05-30 21:57 ivan + + * FS/FS/part_export/netsapiens.pm: necessary for + bin/cdr-netsapeins.import + +2009-05-30 05:15 ivan + + * FS/FS/Schema.pm: very long transnexus filenames, RT#5229 + +2009-05-30 04:21 ivan + + * FS/FS/cdr/transnexus.pm: clid is base-64 encoded, huh, RT#5229 + +2009-05-30 04:14 ivan + + * bin/cdr-transnexus.import: quick hacked-up copy of + freeside-cdr-sftp_and_import for transnexus directory structure, + RT#5229 + +2009-05-30 03:45 ivan + + * FS/FS/: cdr.pm, cdr/transnexus.pm: add transnexus format, RT#5229 + +2009-05-29 20:40 ivan + + * FS/FS/part_pkg/prepaid.pm: and enable overlimit_action, RT#4995 + +2009-05-29 20:14 ivan + + * FS/FS/: svc_acct.pm, part_pkg/flat.pm, part_pkg/prepaid.pm: add + ability for prepaid packages to have usage limits and cancel if + they're hit, RT#4995 + +2009-05-29 19:31 ivan + + * FS/FS/: Conf.pm, svc_acct.pm: require svc_acct-usage_threshold to + be set explicitly, don't default to 80% + +2009-05-29 16:36 ivan + + * httemplate/search/cdr.html: slightly better labels and field + order for CDR report, RT#4081 + +2009-05-29 16:17 ivan + + * FS/FS/: Conf.pm, cdr.pm, cdr/netcentrex.pm: fixup pivot code + handling in netcentrex CDR handling, RT#4081 + +2009-05-28 21:43 jeff + + * FS/FS/Conf.pm: correct description to reflect previous changes + +2009-05-28 17:22 jeff + + * httemplate/edit/: quick-charge.html, process/quick-charge.cgi: + don't require a leading 0 in the quick charge amount + +2009-05-27 15:32 ivan + + * httemplate/search/cust_bill_pkg.cgi: and multiple taxlcasses. i + think that should actually do it for now on RT#5446 + +2009-05-27 15:23 ivan + + * httemplate/search/report_tax.cgi: and the "tax invoiced" link + too! woo, working, RT#5446 + +2009-05-27 15:13 ivan + + * httemplate/search/: cust_bill_pkg.cgi: maybe this willf inally + fix total line links on tax report when using report_group + kludge? (still possibly not in all corner cases), RT#5446 + +2009-05-27 15:10 ivan + + * httemplate/search/: cust_bill_pkg.cgi, report_tax.cgi: maybe this + willf inally fix total line links on tax report when using + report_group kludge? (still possibly not in all corner cases), + RT#5446 + +2009-05-27 14:35 ivan + + * httemplate/search/report_tax.cgi: fix total line links on tax + report when using report_group kludge? (possibly not in all + corner cases), RT#5446 + +2009-05-27 14:27 ivan + + * httemplate/search/report_tax.cgi: fix total line links on tax + report when using report_group kludge? (possibly not in all + corner cases), RT#5446 + +2009-05-27 14:24 jeff + + * httemplate/elements/menuarrow.gif: close ticket 1517 + +2009-05-27 10:18 ivan + + * httemplate/search/: cust_bill_pkg.cgi, report_tax.cgi: fix total + line links on tax report when using report_group kludge? + (possibly not in all corner cases), RT#5446 + +2009-05-27 00:50 jeff + + * FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/cust_main.pm, + FS/FS/cust_recon.pm, FS/MANIFEST, FS/FS/cust_pkg.pm, + FS/FS/svc_acct.pm, FS/FS/ClientAPI/Bulk.pm, + FS/FS/part_pkg/voip_cdr.pm, FS/bin/freeside-selfservice-server, + FS/t/cust_recon.t, fs_selfservice/FS-SelfService/MANIFEST, + fs_selfservice/FS-SelfService/Makefile.PL, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/freeside-selfservice-clientd, + fs_selfservice/FS-SelfService/freeside-selfservice-soap-server, + fs_selfservice/FS-SelfService/iZoomOnlineProvisionService.pm: + bulk provisioning via ftp and SOAP #5202 + +2009-05-26 05:32 jeff + + * fs_selfservice/FS-SelfService/cgi/: overlibmws.js, + overlibmws_crossframe.js, overlibmws_draggable.js, + overlibmws_iframe.js, iframecontentmws.js: include overlib in + selfservice + +2009-05-25 19:48 ivan + + * httemplate/search/report_tax.cgi: and also fix "tax invoiced" + portion of total line when using config option for some basic tax + grouping by name, RT#5446 + +2009-05-25 19:03 ivan + + * httemplate/search/report_tax.cgi: mostly fix total line when + using config option for some basic tax grouping by name, RT#5446 + +2009-05-25 18:41 ivan + + * httemplate/search/: report_tax.html, report_tax.cgi: add a config + option for some basic tax grouping by name, RT#5446 + +2009-05-25 18:35 ivan + + * FS/FS/Conf.pm, httemplate/search/report_tax.cgi, + httemplate/search/report_tax.html: add a config option for some + basic tax grouping by name, RT#5446 + +2009-05-25 15:42 ivan + + * httemplate/graph/cust_bill_pkg.cgi: fix total links on sales + graph when a package class is specified, RT#5449 + +2009-05-24 20:59 ivan + + * fs_selfservice/FS-SelfService/cgi/selfservice.cgi: international + self-service payments, RT#1592 + +2009-05-24 18:49 ivan + + * FS/FS/ClientAPI/MasonComponent.pm, FS/FS/ClientAPI/MyAccount.pm, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/cgi/card.html, + fs_selfservice/FS-SelfService/cgi/make_payment.html, + fs_selfservice/FS-SelfService/cgi/selfservice.cgi, + fs_selfservice/FS-SelfService/cgi/misc/counties.cgi, + fs_selfservice/FS-SelfService/cgi/misc/states.cgi, + httemplate/elements/location.html, + httemplate/elements/select-county.html: international + self-service payments, RT#1592 + +2009-05-21 20:22 ivan + + * FS/bin/freeside-upgrade: commit before sqlradius upgrade so + sqlradius upgrade errors from permissions can be ignored for now + +2009-05-21 20:02 ivan + + * FS/FS/cust_pkg.pm, httemplate/search/report_cust_pkg.html: add + ability to report on packages w/status "not yet billed" as well, + RT#5409 + +2009-05-20 08:27 ivan + + * FS/FS/Conf.pm, httemplate/view/cust_main/packages.html, + httemplate/view/cust_main/packages/services.html: add "manage + device" link & config, RT#5438 + +2009-05-20 01:27 ivan + + * FS/FS/part_export/netsapiens.pm: get subscriber deletion working + and remove devel cruft, RT#5226 + +2009-05-19 18:06 ivan + + * FS/FS/part_export/netsapiens.pm: first pass at netsapiens + integration, RT#5226 + +2009-05-18 12:23 jeff + + * FS/FS/tax_rate_location.pm: miss use + +2009-05-18 12:21 jeff + + * FS/FS/Schema.pm: allow empty state + +2009-05-18 11:21 jeff + + * FS/bin/freeside-upgrade: prevent death on meritless sqlradius + upgrade attempts + +2009-05-18 02:55 ivan + + * FS/FS/cust_svc.pm, FS/FS/ClientAPI/MyAccount.pm, + FS/FS/UI/bytecount.pm, + fs_selfservice/FS-SelfService/cgi/header.html, + fs_selfservice/FS-SelfService/cgi/selfservice.cgi, + fs_selfservice/FS-SelfService/cgi/view_cdr_details.html, + fs_selfservice/FS-SelfService/cgi/view_usage.html, + fs_selfservice/FS-SelfService/SelfService.pm: basic CDR viewing + from self-service, RT#4018 + +2009-05-18 01:40 ivan + + * FS/bin/freeside-cdr-sftp_and_import: it would help to use the + correct port, RT#4081 + +2009-05-17 21:56 jeff + + * FS/FS/: part_pkg_taxrate.pm, tax_rate.pm: handle dates before + 1970 + +2009-05-16 13:07 rsiddall + + * FS/FS/part_export/domreg_opensrs.pm: Added information on common + failure causes to the perldoc. + +2009-05-16 12:27 rsiddall + + * FS/FS/part_export/domreg_opensrs.pm: Defer use of Net::OpenSRS so + that failure to install the module doesn't stop Apache from + starting. (This causes attempts to register domains to fail + instead.) + +2009-05-15 19:29 rsiddall + + * FS/FS/part_export/domreg_opensrs.pm: Provide better diagnostics + when the cust_main owning this domain does not provide fields + required for use as a contact handle in the domain registration + record. Also temporarily disable the ability to have the export + do only registration or only transfers. + +2009-05-15 12:41 rsiddall + + * FS/FS/svc_domain.pm, FS/FS/part_export/domreg_opensrs.pm, + httemplate/edit/part_export.cgi, httemplate/edit/svc_domain.cgi, + httemplate/edit/process/part_export.cgi, + httemplate/edit/process/svc_domain.cgi: Simple domain + registration at Tucows OpenSRS using an export based on + Net::OpenSRS. When a domain is added and the export runs, it + will register the domain or initiate a transfer. You can also + choose no action. There's currently no provision for revoking + domains or renewing registrations. Depending on the settings at + OpenSRS, orders may look like they've succeeded in Freeside but + actually be queued pending input by the reseller at OpenSRS. The + part_export CGIs were modified to allow a multi-valued select to + be used to control which TLDs are enabled for registration. + +2009-05-14 09:26 jeff + + * httemplate/edit/cust_main/bottomfixup.js: ask for help assignting + geocode more often + +2009-05-14 09:25 jeff + + * httemplate/view/cust_main/billing.html: show geocode when + taxproducts enabled + +2009-05-13 15:27 jeff + + * FS/FS/Schema.pm, FS/FS/cust_bill_pkg.pm, + FS/FS/cust_bill_pkg_tax_rate_location.pm, FS/FS/cust_main.pm, + FS/FS/tax_rate_location.pm, FS/MANIFEST, FS/FS/tax_rate.pm, + FS/t/cust_bill_pkg_tax_rate_location.t, FS/t/tax_rate_location.t, + bin/tax_rate_location.import, httemplate/misc/tax-import.cgi, + httemplate/search/cust_bill_pkg.cgi, + httemplate/search/report_newtax.cgi: improved taxproduct tax + report RT#4783 + +2009-05-12 17:51 ivan + + * conf/invoice_latex: remove obsolete comments + +2009-05-09 17:45 ivan + + * FS/FS/svc_phone.pm: label phone_name correctly + +2009-05-09 16:54 ivan + + * FS/bin/freeside-cdr-sftp_and_import, bin/cdr.sftp_and_import: + move cdr-sftp_and_import script to FS/bin, add -p option, RT#4081 + +2009-05-09 00:56 ivan + + * FS/FS/: Conf.pm, cdr.pm: add + cdr-charged_party-truncate_{length,prefix} in order to trim + charged_party to a certain length, RT#4081 + +2009-05-08 18:44 ivan + + * httemplate/: edit/elements/svc_Common.html, + edit/elements/edit.html, view/elements/svc_Common.html: use + service-def specific labels, at least for service pages that use + {view,edit}/elements/svc_Common.html RT#4081 + +2009-05-08 17:39 ivan + + * FS/FS/Schema.pm, FS/FS/part_svc.pm, FS/FS/part_svc_column.pm, + FS/FS/svc_acct.pm, httemplate/browse/part_svc.cgi, + httemplate/edit/part_svc.cgi: add ability to configure service + labels per-package (still need to actually use the labels), + RT#4081 + +2009-05-08 01:41 ivan + + * httemplate/edit/part_pkg.cgi: fix cloning of custom packages + where you've changed '(CUSTOM)', RT#5350 + +2009-05-05 15:02 ivan + + * FS/FS/Conf.pm, httemplate/edit/agent.cgi: hide + agent.invoice_template edit by default, with a config to turn + back on, RT#5218 + +2009-05-05 10:58 ivan + + * FS/FS/cust_pay.pm: add company_name to payment receipt + +2009-05-05 03:40 ivan + + * FS/FS/rate_detail.pm, httemplate/elements/file-upload.html, + httemplate/misc/rate_edit_excel.html, + httemplate/misc/process/rate_edit_excel.html: finish the import + portion of excel rate edit, RT#5108 + +2009-05-04 18:41 jeff + + * bin/cust_main_special.pm: ignore fee based taxes and eliminate + unused code + +2009-05-04 11:33 jeff + + * bin/: cust_main_special.pm, rebill: this is a quick hack to + rebill customers when a cdr didn't happen + +2009-05-03 19:01 ivan + + * httemplate/search/: report_prepaid_income.cgi, + report_prepaid_income.html: agent-virt prepaid income report, + RT#5311 + +2009-05-03 18:17 ivan + + * FS/FS/svc_acct.pm: eliminate Argument "" isn't numeric in + addition (+) warning + +2009-05-03 17:22 ivan + + * httemplate/: browse/rate_region.html, elements/menu.html, + misc/rate_edit_excel.html, search/elements/search-xls.html, + search/elements/search.html: add menu item and page for d/ling + and edit rates with excel. RT#5108 + +2009-05-03 15:45 ivan + + * httemplate/search/elements/: search-csv.html, search-html.html, + search-xls.html, search.html: break down search.html into + components, RT#5108 + +2009-05-03 11:34 ivan + + * FS/FS/AccessRight.pm, httemplate/search/cust_pay_batch.cgi: add + "Redownload resolved batches" ACL for s1, RT#4271 + +2009-05-02 20:13 ivan + + * httemplate/config/config.cgi: edit any config item + +2009-05-02 18:45 ivan + + * httemplate/config/config-view.cgi: add ability to delete + invoice_latexreturnaddress and invoice_htmlreturnaddress too, + RT#5218 + +2009-05-02 18:11 ivan + + * FS/FS/Conf.pm, httemplate/config/config-delete.cgi, + httemplate/config/config-view.cgi: add ability to remove + suffix-ed config items, RT#5218 + +2009-05-02 17:40 ivan + + * bin/confdiff: confdiff + +2009-05-02 15:11 ivan + + * FS/FS/Misc/eps2png.pm: fix eps preview + +2009-05-01 17:01 ivan + + * httemplate/: browse/agent.cgi, config/config-delete.cgi, + config/config-process.cgi, config/config-view.cgi: finish up + useful agent stuff on the config editor: adding, deleting + overrides too. also add a confirmation to override deletion from + the agent browse page. RT#5218 + +2009-05-01 13:21 jeff + + * FS/FS/cust_main.pm: calculate tax on tax per line and not on + aggregate + +2009-04-30 19:43 ivan + + * httemplate/config/config-view.cgi: view all overrides when asked, + even the ones without values. hmm :/ RT#5218 + +2009-04-30 19:08 ivan + + * FS/FS/cust_event.pm: fix re-print/email from event page, yow. + RT#5293 + +2009-04-30 18:07 ivan + + * httemplate/config/: config-process.cgi, config-view.cgi: add + ability to edit the agent overrides from the main config, RT#4218 + +2009-04-29 11:25 ivan + + * httemplate/edit/svc_www.cgi: fix inadvertant select box, RT#5277 + +2009-04-28 15:38 ivan + + * fs_selfservice/FS-SelfService/cgi/bill.html: UI + +2009-04-27 21:36 ivan + + * FS/FS/cust_main.pm: add cancelled_cust-noevents flag to emulate + SG billing-daily -r behavior, RT#4412 + +2009-04-27 21:13 ivan + + * FS/FS/: Conf.pm, cust_main.pm: add cancelled_cust-noevents flag + to emulate SG billing-daily -r behavior + +2009-04-27 16:06 ivan + + * FS/FS/Mason.pm: typo + +2009-04-27 16:01 ivan + + * FS/FS/Mason.pm: refuse to run w/CGI.pm 3.38. all lenny upgrades + will need libcgi-pm-perl removed, suck + +2009-04-26 16:43 ivan + + * FS/FS/Schema.pm: would help to have an index on priority if we're + going to order based on it + +2009-04-26 16:19 ivan + + * FS/bin/freeside-queued: start small jobs more efficiently, + RT#4412 + +2009-04-26 16:09 ivan + + * FS/FS/Conf.pm: add a config option for max # of queued kids, + RT#4412 + +2009-04-25 15:42 ivan + + * FS/: FS/Cron/bill.pm, bin/freeside-daily: add dry run to + multi-process mode for testing, RT#4412 + +2009-04-23 13:34 jeff + + * FS/FS/: Upgrade.pm, part_pkg_option.pm, part_pkg/voip_cdr.pm: add + subscription option to voip_cdr + +2009-04-23 13:31 jeff + + * httemplate/misc/tax-fetch_and_import.cgi, + httemplate/misc/process/tax-fetch_and_import.cgi, FS/FS/Conf.pm, + FS/FS/cust_tax_location.pm, FS/FS/part_pkg_taxrate.pm, + FS/FS/tax_class.pm, FS/FS/tax_rate.pm, + httemplate/elements/menu.html: autodownload and update of cch tax + data + +2009-04-22 21:57 ivan + + * FS/FS/Cron/bill.pm: we don't actually need the results ordered, + and i'm sure it doesn't help the planner get us results sooner. + last chance to try and get cursor approach working? RT#4412 + +2009-04-22 21:14 ivan + + * FS/FS/Cron/bill.pm: does pg try to finish the query when the job + addition is committed? well, if this works, that answers that. + RT#4412 + +2009-04-22 13:24 ivan + + * FS/FS/Cron/bill.pm: hopefully better performance running the big + query once and then fetching results with a cursor, rather than + running it multiple times with an OFFSET and LIMIT, RT#4412 + +2009-04-22 11:58 ivan + + * httemplate/edit/process/cust_main.cgi: fix not allowing + "on-demand" card or ACH, RT#5238 RT#5237 RT#5230 + +2009-04-21 23:52 ivan + + * FS/FS/Cron/bill.pm: perhaps a happier medium, RT#4412 + +2009-04-21 17:54 ivan + + * FS/FS/Cron/bill.pm: have the big query find customers in batches. + this should be way more efficient in multi-process mode, can + start billing before the big query completes. RT#4412 + +2009-04-21 13:59 ivan + + * httemplate/browse/rate_region.html: rate download/edit/upload, + RT#5108 + +2009-04-21 13:28 ivan + + * httemplate/browse/rate_region.html: rate download/edit/upload, + RT#5108 + +2009-04-21 09:42 ivan + + * FS/FS/Cron/bill.pm: yow. fix fallout from cust_main.archived + stuff causing nothing to bill. RT#4412 + +2009-04-20 19:23 jeff + + * FS/FS/UI/Web.pm, httemplate/elements/progress-popup.html: more + descriptive progress popups + +2009-04-20 13:57 rsiddall + + * rpm/freeside.spec: Acceptance testing of the RPM build system + flushed out a place where /bin/rm stops waiting for input if + you're /bin/su as the user doing the build. Added a -f flag to + stop it waiting for input. + +2009-04-20 09:57 ivan + + * FS/FS/: Schema.pm, cust_main.pm, Cron/bill.pm: add + cust_main.archived field, skip billing if Y, RT#4412 + +2009-04-19 16:55 ivan + + * bin/h_cust_main-wipe_paycvv: no, it was only cause their db is + somehow corrupt + +2009-04-19 16:52 ivan + + * bin/h_cust_main-wipe_paycvv: warning about this not terminating + +2009-04-17 16:30 ivan + + * bin/: fs-migrate-cust_tax_exempt, h_cust_main-wipe_paycvv: + something to wipe the CVV from very large databases + +2009-04-17 12:50 ivan + + * FS/: FS/Schema.pm, FS/Cron/bill.pm, bin/freeside-queued: add + priority to job queue so billing jobs don't don't drown out + provisioning jobs + +2009-04-17 12:21 ivan + + * FS/FS/Cron/bill.pm: 1 helps alot + +2009-04-17 12:20 ivan + + * FS/bin/freeside-daily: backport freeside-daily -m and + cust_main::bill_and_collect to 1.7, RT#4412 + +2009-04-17 01:25 ivan + + * httemplate/docs/about.html: AFFERO BITCHES + +2009-04-17 01:16 ivan + + * httemplate/docs/about.html: what time is now + +2009-04-17 01:02 ivan + + * httemplate/config/: config-process.cgi, config-view.cgi, + config.cgi: show labels for select(select_hash) config options, + RT#3997 + +2009-04-17 00:21 ivan + + * FS/FS/cust_bill.pm: add invoice number to PDF filename in email + attachments, RT#3403 + +2009-04-17 00:03 ivan + + * httemplate/elements/header.html, + rt/html/Elements/FreesideSvcSearch: hide service search unless + user has "View customer services" ACL, RT#3478 + +2009-04-16 18:17 ivan + + * httemplate/search/: report_receivables.cgi, + report_receivables.html: add customer status to receivables + report selection, hopefully help enet, RT#5187 + +2009-04-15 20:58 rsiddall + + * rpm/freeside.spec: More fixes for SuSE self-service: 1/ Put + binaries in the right folder 2/ Make sure freeside group is + created 3/ Make sure freeside home directory is created + +2009-04-15 00:14 ivan + + * httemplate/view/: svc_Common.html, elements/svc_Common.html: + should fix view of unlinked phone numbers, RT#5171 + +2009-04-14 22:52 ivan + + * httemplate/view/svc_acct.cgi: s/GECOS/Real Name/ RT#3519 + +2009-04-14 19:44 ivan + + * FS/FS/ClientAPI/MyAccount.pm: fix 1.7->1.9 upgrade glitch with + self-service where process_payment required "payby" instead of + defaulting to CARD, RT#3905 + +2009-04-14 19:29 ivan + + * FS/FS/cust_bill.pm: show 60 chars on typeset invoices but only 32 + on plaintext, RT#3905 + +2009-04-14 19:15 ivan + + * FS/FS/cust_bill.pm: this should fix credits pushing typeset + invoices off the right + +2009-04-14 14:01 ivan + + * httemplate/view/cust_main/packages.html: remove debugging + +2009-04-14 13:27 ivan + + * httemplate/view/cust_main/packages.html: don't hide old packages + that have services, RT#5179 + +2009-04-14 10:15 ivan + + * FS/FS/: cust_main.pm, agent.pm: add configuration option to + control recurring_flag behavior, RT#3843 + +2009-04-14 10:12 ivan + + * FS/FS/: Conf.pm, Schema.pm: add configuration option to control + recurring_flag behavior, RT#3843 + +2009-04-14 09:14 jeff + + * httemplate/misc/process/tax-import.cgi: hmmm + +2009-04-14 09:12 jeff + + * httemplate/misc/process/tax-import.cgi: better at least + +2009-04-13 17:09 ivan + + * FS/FS/Conf.pm: add configuration option to control recurring_flag + behavior, RT#3843 + +2009-04-13 16:37 ivan + + * FS/FS/cust_main.pm: debugging + +2009-04-11 23:24 ivan + + * httemplate/elements/tr-select-svc_acct-domain.html: adding + +2009-04-11 23:14 ivan + + * httemplate/elements/selectlayers.html: add svc_phone on new + customer first package, RT#4315 + +2009-04-11 23:09 ivan + + * FS/FS/part_pkg.pm, httemplate/edit/cust_main.cgi, + httemplate/edit/cust_main/birthdate.html, + httemplate/edit/cust_main/bottomfixup.html, + httemplate/edit/cust_main/bottomfixup.js, + httemplate/edit/cust_main/first_pkg.html, + httemplate/edit/cust_main/top_misc.html, + httemplate/edit/cust_main/billing.html, + httemplate/edit/cust_main/choose_tax_location.html, + httemplate/edit/cust_main/select-domain.html, + httemplate/edit/cust_main/first_pkg/select-part_pkg.html, + httemplate/edit/cust_main/first_pkg/svc_acct.html, + httemplate/edit/cust_main/first_pkg/svc_phone.html, + httemplate/edit/process/cust_main.cgi, + httemplate/elements/select-domain.html, + httemplate/misc/part_svc-columns.cgi, + httemplate/elements/select-svc_acct-domain.html: add svc_phone on + new customer first package, RT#4315 + +2009-04-11 18:33 jeff + + * etc/fslongtable.sty: sheesh + +2009-04-11 18:24 jeff + + * Makefile, etc/fslongtable.sty, conf/invoice_latex: find and + correct the real double counting culprit + +2009-04-11 14:42 ivan + + * FS/FS/part_event/Action/writeoff.pm, bin/freeside-migrate-events: + migrate send_email, suspend_if_balance and credit events, RT#3905 + +2009-04-11 14:29 ivan + + * FS/FS/part_event/Action/cust_bill_email.pm: add cust_bill_email + action + +2009-04-11 13:51 ivan + + * FS/bin/freeside-upgrade: don't run configuration update when -s + is used for schema-only slony slave update + +2009-04-10 12:33 ivan + + * FS/FS/Conf.pm: better description for enable_taxproducts and a + warning about tax-pkg_address with it + +2009-04-09 20:43 jeff + + * FS/FS/cust_main.pm: orders of magnitude faster + +2009-04-09 15:51 jeff + + * FS/FS/cdr/taqua.pm: used BillingNumber and not CallingPartyNumber + for non-toll-free calls + +2009-04-08 15:42 ivan + + * FS/FS/cust_pkg.pm: fix 'agent X can't purchase pkgpart YY' error + w/agent packages, RT#5119 + +2009-04-08 01:08 ivan + + * FS/FS/Cron/check.pm: don't want to throw false positives, RT#5101 + +2009-04-08 00:32 ivan + + * FS/FS/: Record.pm, Upgrade.pm, cust_main.pm: eliminate all trace + of cvv from history records, RT#5093 + +2009-04-07 18:13 ivan + + * httemplate/misc/link.cgi: when linking a legacy phone number the + phone number could be typed in and not the service #. RT#3407 + +2009-04-07 13:45 jeff + + * FS/FS/: cdr.pm, cdr/taqua.pm: quick option to allow importing gmt + cdrs + +2009-04-07 11:20 ivan + + * FS/FS/: Conf.pm, svc_acct.pm: add a config to allow colon in + usernames, RT#5145 + +2009-04-07 11:15 ivan + + * FS/FS/svc_acct.pm: truncate long labels that are TOO long... + RT#3519 + +2009-04-06 19:50 jeff + + * FS/FS/cdr.pm: a tollfree regex that captures 88x and works with + +1 + +2009-04-06 19:18 ivan + + * FS/FS/cdr.pm: stop smoking crack + +2009-04-06 18:20 jeff + + * FS/FS/: Record.pm, cdr.pm, cdr/taqua.pm, part_pkg/voip_cdr.pm: + correct taqua toll free handling and hasten cdr import (skip + uninteresting records) + +2009-04-06 16:19 jeff + + * FS/FS/part_pkg/voip_cdr.pm: better auto toll free regex + +2009-04-06 11:31 jeff + + * FS/FS/cdr/taqua.pm: calltype 6 is international + +2009-04-05 17:52 jeff + + * Makefile, etc/fslongtable.sty: stop doublecounting + extracouponspace but do not gratuitiously change existing + installs + +2009-04-05 16:18 jeff + + * FS/FS/cust_main.pm: cleanup tax-pkg_location tax on tax fallout + +2009-04-04 09:22 jeff + + * FS/FS/: Schema.pm, cust_bill_pkg_detail.pm: correct bad schema + bug in cust_bill_pkg_detail + +2009-04-03 09:57 jeff + + * FS/FS/part_pkg/voip_cdr.pm: add option for available rather than + provisioned svc_phones as unit count + +2009-04-02 13:22 jeff + + * httemplate/edit/cust_main/billing.html: Net 20 as well + +2009-04-02 10:47 jeff + + * FS/FS/part_pkg/voip_cdr.pm: separate checkbox for enabling + prorate feature + +2009-04-02 08:46 jeff + + * FS/FS/part_pkg/voip_cdr.pm: prorating for the fixed recurring + portion of voip + +2009-04-02 07:56 jeff + + * httemplate/edit/cust_main.cgi: obey tax-ship_address in 'manual' + geocoding + +2009-04-01 22:27 jeff + + * FS/FS/part_pkg_taxrate.pm: noise reduction + +2009-04-01 19:36 ivan + + * FS/FS/part_pkg/voip_cdr.pm: more than you ever wanted to know + about rounding. http://en.wikipedia.org/wiki/Rounding RT#4666 + +2009-04-01 17:14 ivan + + * httemplate/browse/part_pkg.cgi: add some + (undocumented/unaccessable to web UI yet) options to package + browse to track down packages missing recurring fees + +2009-03-31 21:27 ivan + + * FS/FS/cdr.pm: show post-granularity duration if available for all + export formats + +2009-03-31 20:51 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add options to skip CDRs under a + defined length and with specific lastapp + +2009-03-31 20:44 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add options to skip CDRs under a + defined length and with specific lastapp + +2009-03-31 12:51 ivan + + * FS/FS/Cron/notify.pm: really fix notify for Pg 8.3 + +2009-03-31 12:47 ivan + + * FS/FS/part_pkg/voip_cdr.pm: quiet warning: Argument "" isn't + numeric in numeric eq (==) at + /usr/local/share/perl/5.10.0/FS/part_pkg/voip_cdr.pm line 201 + +2009-03-31 12:46 ivan + + * FS/FS/Cron/notify.pm: fix impending billing notification for Pg + 8.3's more strict type checking + +2009-03-30 09:33 jeff + + * FS/FS/cust_tax_location.pm: schema and module should agree on + column names + +2009-03-29 23:10 ivan + + * FS/FS/cust_main.pm, FS/FS/cust_pkg.pm, + httemplate/view/cust_main/packages.html: okay. counts are needed + for the package sort, so push the embedded counting into + cust_main.pm. sure hope this does it. RT#5083 + +2009-03-29 22:08 ivan + + * FS/FS/cust_pkg.pm: and hopefully actually using the count will + finally do it, RT#5083 + +2009-03-29 21:50 ivan + + * FS/FS/cust_pkg.pm: and hopefully actually using the count will + finally do it, RT#5083 + +2009-03-29 21:41 ivan + + * httemplate/view/cust_main/packages.html: double doh! RT#5083 + +2009-03-29 21:35 ivan + + * httemplate/view/cust_main/packages.html: doh! underscore, + RT#5083 + +2009-03-29 21:31 ivan + + * httemplate/view/cust_main/packages.html: try not to search for + nothing in cust_svc so much, RT#5083 + +2009-03-29 21:15 ivan + + * FS/FS/cust_pkg.pm, httemplate/view/cust_main/packages.html: try + not to search for nothing in cust_svc so much, RT#5083 + +2009-03-29 20:47 ivan + + * FS/FS/cust_main.pm: didn't need this, but more future-proof, + RT#5083 + +2009-03-29 20:12 ivan + + * httemplate/view/cust_main/packages.html: really prevent separate + part_pkg query, RT#5083 + +2009-03-29 18:39 ivan + + * httemplate/view/cust_main/packages.html: doh, fix pkg display, + RT#5083 + +2009-03-29 18:28 ivan + + * httemplate/view/cust_main/packages.html: fix setup date display, + RT#5083 + +2009-03-29 18:09 ivan + + * httemplate/view/cust_main/packages.html: forget caching, instead + scoop up cust_pkg and part_pkg in one query, RT#5083 + +2009-03-29 18:05 ivan + + * FS/FS/cust_main.pm, httemplate/view/cust_main/packages.html: + forget caching, instead scoop up cust_pkg and part_pkg in one + query, RT#5083 + +2009-03-29 17:32 ivan + + * FS/FS/cust_pkg.pm, httemplate/view/cust_main/packages.html: + part_pkg caching should speedup display of lots of packages, + RT#5083 + +2009-03-29 16:44 ivan + + * FS/FS/Conf.pm, httemplate/view/cust_main/packages.html: hide over + 2 (or configured) cancelled and one-time charge packages, RT#5083 + +2009-03-29 04:56 ivan + + * FS/FS/Schema.pm: index pkg_svc.quantity, RT#5083 + +2009-03-29 04:52 ivan + + * FS/FS/cust_pkg.pm: seems to benchmark faster, RT#5083 + +2009-03-29 03:39 ivan + + * httemplate/view/cust_main/packages/package.html: avoid looking up + part_pkg redundantly in the pkg loop, RT#5083 + +2009-03-29 03:34 ivan + + * httemplate/view/cust_main/packages/package.html: avoid looking up + package details redundantly in the pkg loop, RT#5083 + +2009-03-29 03:17 ivan + + * FS/FS/: Record.pm, cust_pkg.pm: add "extra_param" option to + qsearch for more realisitic profiling data, RT#5083 + +2009-03-29 02:38 ivan + + * httemplate/view/cust_main/: one_time_charge_link.html, + packages.html, packages/status.html: optimize customer view when + there's lots of packages; *really* avoid looking up any config + inside the package loop, RT#5083 + +2009-03-28 15:59 ivan + + * httemplate/elements/select-cust-part_pkg.html, + httemplate/elements/select-cust-pkg_class.html, + httemplate/elements/select-part_pkg.html, + httemplate/elements/select-table.html, + httemplate/elements/tr-select-cust-part_pkg.html, + httemplate/elements/tr-selectmultiple-part_pkg.html, + FS/FS/Conf.pm, FS/FS/part_pkg.pm, httemplate/misc/change_pkg.cgi, + httemplate/misc/cust-part_pkg.cgi, + httemplate/misc/order_pkg.html: package selector, split by + package class, RT#5077 + +2009-03-25 20:59 ivan + + * FS/FS/svc_acct.pm: yow + +2009-03-25 20:53 ivan + + * FS/FS/cust_main.pm: sort packages by label of first (primary) + service, RT#5041 + +2009-03-25 02:36 ivan + + * httemplate/pref/pref-process.html: throw a proper error message + instead of a mason error on pw chagne problems, RT#5073 + +2009-03-25 02:36 ivan + + * httemplate/pref/pref.html: we're defaulting to a top menu in 1.9 + +2009-03-25 01:45 ivan + + * FS/FS/cdr.pm: correct headers on accountcode_default CDR output, + RT#5042 + +2009-03-24 02:42 ivan + + * bin/countdeclines: quick tool for RT#3843 + +2009-03-23 23:31 ivan + + * FS/FS/Schema.pm: add indices for analyzing cc failures, RT#3843 + +2009-03-23 19:36 ivan + + * FS/FS/: part_pkg/bulk.pm, Record.pm, cust_bill.pm, cust_svc.pm, + h_cust_svc.pm, part_pkg.pm: bulk price plan: label as Name + , supress extraneous service list, RT#3519 + +2009-03-23 16:33 jeff + + * FS/FS/cust_pkg.pm, FS/FS/svc_acct.pm, FS/FS/part_pkg/flat.pm, + httemplate/misc/process/recharge_svc.html: more DTRT with usage + on service transfer between packages and recharges RT #2884, + #5040 + #4995 fallout + +2009-03-23 15:45 ivan + + * httemplate/edit/svc_acct.cgi: change label for svc_acct.finger + from GECOS to "Real Name", RT#3519 + +2009-03-23 10:02 ivan + + * FS/FS/: svc_Common.pm, svc_acct.pm, part_pkg/bulk.pm: add name + (svc_acct.finger) to bulk billing detail, RT#3519 + +2009-03-21 20:33 ivan + + * FS/FS/Cron/check.pm: 10 is too few, throwing false positives + +2009-03-21 19:47 ivan + + * httemplate/misc/xmlhttp-cust_main-address_standardize.html: fix + usps address standardization when the zip returned has no zip+4, + RT#4882 + +2009-03-21 16:37 ivan + + * FS/bin/freeside-check: Locale::SubCountry warnings clogging up + cron output not useful + +2009-03-21 16:32 ivan + + * FS/FS/Cron/check.pm: 403 forbidden is okay, at lest the server's + up + +2009-03-21 15:14 ivan + + * Makefile, FS/FS/Cron/check.pm, FS/bin/freeside-check: + freeside-check local monitoring, RT#4610 + +2009-03-19 19:14 ivan + + * bin/ping: adding quick remote ping & alert script, RT#4610 + +2009-03-18 08:11 jeff + + * FS/FS/part_pkg_taxrate.pm: more error information + +2009-03-17 17:30 jeff + + * FS/FS/svc_acct.pm, FS/FS/part_pkg/flat.pm, + httemplate/edit/part_svc.cgi: hide unused usage columns + +2009-03-17 15:02 ivan + + * fs_selfservice/FS-SelfService/SelfService.pm: add + payment_info_renew_info method to ClientAPI/MyAccount and + SG-equivalent previous_payment_info_renew_info to ClientAPI/SGNG + +2009-03-17 14:38 ivan + + * FS/FS/ClientAPI/SGNG.pm, FS/FS/ClientAPI/MyAccount.pm, + fs_selfservice/FS-SelfService/SelfService.pm: add + payment_info_renew_info method to ClientAPI/MyAccount and + SG-equivalent previous_payment_info_renew_info to ClientAPI/SGNG + +2009-03-17 13:41 ivan + + * fs_selfservice/FS-SelfService/SelfService.pm: add SG stuff + +2009-03-17 13:13 ivan + + * FS/FS/Conf.pm: add a conf switch to enable sg multicust stuff, + since it could be dangerous + +2009-03-17 13:04 ivan + + * FS/FS/Conf.pm: apacheip isn't actually deprecated yet + +2009-03-17 12:48 ivan + + * FS/FS/ClientAPI/SGNG.pm: adding ClientAPI/SGNG.pm + +2009-03-17 09:06 jeff + + * FS/FS/: Upgrade.pm, tax_rate.pm: column upgrade for tax_rate + RT#4903) + +2009-03-17 05:01 ivan + + * FS/FS/: Conf.pm, cust_bill.pm: agent-virt + invoice_*{notes,footer,smallfooter,coupon}, RT#5025 + +2009-03-17 02:59 ivan + + * FS/FS/Misc/eps2png.pm: less debugging + +2009-03-17 02:58 ivan + + * httemplate/docs/credits.html, FS/FS/Conf.pm, FS/FS/Mason.pm, + FS/FS/Misc/eps2png.pm, httemplate/config/config-image.cgi, + httemplate/config/config-view.cgi, httemplate/docs/license.html: + add eps preview to config, for RT#5025 + +2009-03-16 16:28 jeff + + * FS/FS/Schema.pm: avoid the need for approximate comparisons + RT#4903 + +2009-03-16 10:06 jeff + + * FS/FS/Schema.pm, FS/FS/part_export/prizm.pm, + httemplate/edit/svc_broadband.cgi: have prizm use service data + rather than package data to select a profile RT#4853 + +2009-03-16 08:52 jeff + + * bin/make-pkg-fruit: a tool for migrating package elements to + services + +2009-03-16 01:08 jeff + + * FS/FS/svc_broadband.pm: get the dup checking right + +2009-03-16 00:13 ivan + + * httemplate/: misc/payment.cgi, misc/process/payment.cgi, + elements/location.html: allow country selection on credit card + entry, RT#4997 + +2009-03-16 00:13 ivan + + * htetc/: freeside-base1.99.conf, freeside-base1.conf, + freeside-base2.conf: eliminate black diamond arrows on iso-8859-1 + chars in Locale::SubCountry states, RT#4997 + +2009-03-15 23:22 ivan + + * Makefile: 5.10! welcome to the future + +2009-03-15 22:54 ivan + + * httemplate/view/svc_domain.cgi: fix custnum display on domain + view + +2009-03-15 21:21 jeff + + * FS/FS/svc_broadband.pm: use part_svc_router + +2009-03-15 17:57 jeff + + * FS/FS/svc_broadband.pm: comment change + +2009-03-15 15:44 ivan + + * bin/svc_acct-recalculate_usage: adding quick usage resetting tool + +2009-03-15 15:33 ivan + + * FS/FS/cust_svc.pm: don't throw 'Use of uninitialized value in + addition (+) at /usr/local/share/perl/5.8.8/FS/cust_svc.pm line + 626.' error when using attribute_since_sqlradacct + +2009-03-15 12:42 ivan + + * FS/FS/cust_pkg_reason.pm: should give better performance if we + search for what we want instead of using a string match + +2009-03-15 03:46 ivan + + * FS/FS/cust_main.pm: fix application of data fields from prepaid + cards in addition to time field + +2009-03-15 03:34 ivan + + * httemplate/misc/process/recharge_svc.html: apply byte values from + prepaid cards as well as time value, RT#4995 + +2009-03-15 03:30 ivan + + * FS/FS/UI/bytecount.pm, httemplate/edit/prepay_credit.cgi: we're + not a disk drive manufacturer, don't use halfass base-10 + megs/gigs + +2009-03-15 00:33 ivan + + * FS/FS/cust_main.pm: cust_main::payment_info, for + ClientAPI::MyAccount + +2009-03-14 16:44 ivan + + * FS/FS/cust_bill.pm: fix emailed logos to come from db config, not + old files, RT#3093 / RT#4963 + +2009-03-13 11:22 jeff + + * FS/FS/svc_broadband.pm: prevent more duplicate MACs from sneaking + in in the interim + +2009-03-11 03:03 ivan + + * FS/FS/: Conf.pm, cust_bill.pm: add previous_balance-summary_only + config, RT#4404 + +2009-03-11 02:41 ivan + + * FS/FS/cdr.pm: add cdr display with accountcode included, RT#4405 + +2009-03-11 01:57 ivan + + * bin/print-directory_assist: comma + +2009-03-11 01:46 ivan + + * bin/print-directory_assist, etc/areacodes.txt: quick list of area + codes and a kludge to print DA numbers for all of them + +2009-03-10 09:14 jeff + + * fs_selfservice/FS-SelfService/cgi/change_pay.html, + fs_selfservice/FS-SelfService/cgi/make_thirdparty_payment.html, + fs_selfservice/FS-SelfService/cgi/verify.cgi, + fs_selfservice/FS-SelfService/cgi/myaccount.html, + fs_selfservice/FS-SelfService/cgi/myaccount_menu.html, + fs_selfservice/FS-SelfService/cgi/selfservice.cgi, + fs_selfservice/FS-SelfService/cgi/signup.cgi, + fs_selfservice/FS-SelfService/cgi/signup.html, FS/FS/Conf.pm, + FS/FS/Schema.pm, FS/FS/agent.pm, FS/FS/cust_main.pm, + httemplate/elements/tr-textarea.html, FS/FS/cust_pay_pending.pm, + FS/FS/cust_pkg.pm, FS/FS/payby.pm, FS/FS/payment_gateway.pm, + FS/FS/ClientAPI/MyAccount.pm, FS/FS/ClientAPI/Signup.pm, + fs_selfservice/FS-SelfService/SelfService.pm, + httemplate/browse/payment_gateway.html, + httemplate/edit/payment_gateway.html, + httemplate/edit/process/payment_gateway.html: merge webpay + support in with autoselection of old realtime_bop and + realtime_refund_bop + +2009-03-08 17:15 ivan + + * httemplate/misc/svc_acct-domains.cgi: mistake, its back + +2009-03-08 17:15 ivan + + * httemplate/misc/svc_acct-domains.cgi: doh + +2009-03-03 17:47 ivan + + * FS/FS/UID.pm: mpm-itk hack, commented-out for now + +2009-03-03 15:56 ivan + + * FS/FS/UID.pm: show the euid/ruid when throwing the "Not running + uid freeside" error + +2009-03-03 15:41 ivan + + * FS/FS/queue.pm: eliminate harmless "Odd number of elements in + hash assignment" warning + +2009-03-02 00:49 ivan + + * FS/FS/: part_export/vitelity.pm, Schema.pm, phone_avail.pm: + preliminary vitelity export, RT#4868 + +2009-03-01 20:58 ivan + + * FS/: bin/freeside-cdrrewrited, FS/Conf.pm, FS/cdr.pm: option to + do charged_party rewriting in the cdrrewrited daemon, RT#4342 + +2009-03-01 16:10 ivan + + * fs_selfservice/FS-SelfService/cgi/signup.html: have perl + signup.html use selfserice skin config too: selfservice-head, + selfserfice-body_header, selfservice-body_footer, + selfservice-body_bgcolor, selfservice-box_bgcolor + +2009-02-28 10:27 ivan + + * Makefile: avoid erroring out running install-perl-modules when + you have a pristine, un-updated CVS checkout + +2009-02-25 19:51 ivan + + * fs_selfservice/FS-SelfService/cgi/signup.html: make signup for a + bit friendlier for BILL signups for testingm RT#4018 + +2009-02-25 12:05 ivan + + * bin/japan.pl: adding quick tool to change the "states" for japan + +2009-02-24 02:15 ivan + + * FS/FS/Setup.pm: be quiet + +2009-02-24 02:09 ivan + + * conf/report_template: more bootstrapping bs + +2009-02-24 02:06 ivan + + * FS/FS/part_referral.pm: bootstrapping issues + +2009-02-24 02:00 ivan + + * FS/FS/Setup.pm: bootstrapping issues, aaargh + +2009-02-24 01:58 ivan + + * FS/FS/Setup.pm: bootstrapping issues, ugh + +2009-02-24 01:50 ivan + + * FS/FS/part_pkg.pm, FS/bin/freeside-setup, + bin/freeside-create-initial-data: bootstrapping issues + +2009-02-24 01:41 ivan + + * bin/freeside-create-initial-data: somehow rc install wound up + without any data + +2009-02-24 00:45 ivan + + * FS/bin/freeside-cdrrewrited: exact match, RT#3196 + +2009-02-24 00:41 ivan + + * FS/bin/freeside-cdrrewrited, FS/FS/Schema.pm, FS/FS/cdr.pm, + init.d/freeside-init: rewrite CDRs for forwarded Asterisk calls + to be billable, RT#3196 + +2009-02-23 15:52 ivan + + * FS/FS/Conf.pm: fix 1.7 -> 1.9 config upgrade for new "image" + config type + +2009-02-22 13:11 ivan + + * httemplate/view/svc_www.cgi: remove flailing ", RT#4902 + +2009-02-22 13:08 ivan + + * FS/: FS/Upgrade.pm, bin/freeside-upgrade: a better rough idea of + where freeside-upgrade spends time + +2009-02-22 12:42 ivan + + * httemplate/edit/svc_www.cgi: fix apache config editing, doh, + RT#4902 + +2009-02-22 12:12 ivan + + * bin/apache.export: add exportnum to apache export files so they + all get preserved in the case where you're using multiple apache + exports to the same machine, RT#4901 + +2009-02-22 11:46 ivan + + * FS/: MANIFEST, FS/h_cust_pkg.pm, FS/h_cust_pkg_reason.pm, + t/h_cust_pkg.t, t/h_cust_pkg_reason.t, FS/cust_pkg_reason.pm: add + h_cust_pkg and h_cust_pkg_reason packages, RT#4896 + +2009-02-22 02:58 ivan + + * FS/FS/part_pkg/flat.pm: don't do a credit for unused time for + packages that don't have a last bill date. really. RT#4881 + +2009-02-22 02:34 ivan + + * FS/FS/cust_pkg.pm: this would seem to be right, but...? + +2009-02-22 00:41 ivan + + * httemplate/browse/part_pkg.cgi, FS/FS/part_pkg.pm, + FS/FS/type_pkgs.pm: add agent type list to package def browse, + RT#4880 + +2009-02-21 18:37 ivan + + * httemplate/search/: cust_bill_pkg.cgi, report_tax.cgi: fix tax + report for more complex situations with counties and taxclasses, + make taxable line items clickable, RT#4878 + +2009-02-21 16:19 ivan + + * FS/FS/cust_pkg.pm: okay, so no_empty_county was on crack. but + this fixes up tax reports nicely. RT#4878 + +2009-02-21 12:56 ivan + + * FS/FS/cust_pkg.pm: hmm, add no_empty_county option to + location_sql search, for tax reports. RT#4878 + +2009-02-21 12:14 ivan + + * FS/FS/cust_pkg.pm: hmm, add no_empty_county option to + location_sql search, for tax reports. RT#4878 + +2009-02-21 09:56 ivan + + * bin/follow-tax-rename, FS/FS/cust_bill_pkg.pm: adding + follow-tax-rename tool (well, quick hack), RT#4878 + +2009-02-20 20:28 ivan + + * FS/FS/Record.pm: and for obj creation too + +2009-02-20 20:27 ivan + + * FS/FS/Record.pm: it would help to actually finish + nowarn_classload kludge + +2009-02-20 20:23 ivan + + * FS/FS/Record.pm: add nowarn_classload kludge + +2009-02-20 07:07 jeff + + * httemplate/edit/cust_main.cgi: support a default tax location + outside us/ca with cch data and better handling of response from + USPS (RT 4857) + +2009-02-19 18:55 ivan + + * FS/FS/access_user.pm: oops, adding multiple-rightname support + broke ACL caching, bringing it back should be a good perf win for + large customer views, whew. RT#4830 + +2009-02-19 18:41 ivan + + * FS/FS/Conf.pm, httemplate/view/cust_main/packages/status.html: + disable display of auto-suspend dates unless enabled by config. + at least until it can be made more efficient. this is slowing + down customer view waaaaaaaaaay too much. RT#4830 + +2009-02-19 18:22 ivan + + * httemplate/autohandler: harmless tyop + +2009-02-19 05:38 jeff + + * httemplate/edit/: cust_main.cgi, + cust_main/choose_tax_location.html: do not attempt to assign a + geocode to non us/ca addresses (RT 4857) + +2009-02-18 23:57 ivan + + * httemplate/search/: elements/cust_pay_or_refund.html, + elements/search.html, cust_pay_pending.html: redirect pending + payment report back to customer when the pending payment is + resolved, RT#4837, and fix otaker fallout from the pending stuff, + RT#4866 + +2009-02-18 22:42 ivan + + * httemplate/: autohandler, pref/pref-process.html, pref/pref.html: + add profiling to a file OOM situations, RT#4830 + +2009-02-18 17:50 ivan + + * FS/FS/Record.pm: fix "improved" float searching problems, RT#4878 + +2009-02-16 23:43 ivan + + * httemplate/edit/part_pkg.cgi: kludge to clone customer packages + you otherwise couldn't see, RT#4854 + +2009-02-16 23:40 ivan + + * httemplate/edit/part_pkg.cgi: kludge to clone customer packages + you otherwise couldn't see, RT#4854 + +2009-02-16 18:28 ivan + + * FS/FS/Mason.pm, httemplate/autohandler, + httemplate/pref/pref-process.html, httemplate/pref/pref.html: + per-user preference for turning on profiling display when + DBIx::Profile is loaded, RT#4830 + +2009-02-16 18:01 ivan + + * FS/FS/cust_main.pm, httemplate/edit/quick-charge.html, + httemplate/edit/process/quick-charge.cgi, + httemplate/view/cust_main/packages.html: add tax-exempt checkbox + to one-time charges, RT#4858 + +2009-02-16 15:54 ivan + + * FS/FS/cust_pay_pending.pm, FS/FS/AccessRight.pm, + FS/FS/cust_main.pm, httemplate/search/cust_pay_pending.html, + httemplate/search/elements/cust_pay_or_refund.html, + httemplate/edit/cust_pay_pending.html, + httemplate/edit/process/cust_pay_pending.html, + httemplate/view/cust_main/payment_history.html, + httemplate/elements/menu.html: add reporting on (and resolution + of) stuck pending transactions, RT#4837 (RT#3572) + +2009-02-15 22:40 jeff + + * bin/cch_tax_tool: a cheesy little tool to assist in syncing cch + updates to the initial install + +2009-02-15 22:02 jeff + + * FS/FS/: cust_tax_location.pm, part_pkg_taxrate.pm, tax_class.pm: + allow completely empty updates (again?) + +2009-02-15 21:59 jeff + + * FS/FS/cust_tax_location.pm: wrong operator + +2009-02-15 09:38 jeff + + * FS/FS/tax_rate.pm: remove useless line + +2009-02-15 09:23 jeff + + * FS/FS/tax_rate.pm: tyop + +2009-02-15 09:20 jeff + + * FS/FS/tax_rate.pm: trim whitespace on import + +2009-02-15 05:51 jeff + + * FS/FS/Record.pm: improved float searching + +2009-02-13 16:40 ivan + + * httemplate/: elements/select-agent.html, + elements/tr-select-agent.html, browse/addr_block.cgi: clean up + select-agent agent virtualization, RT#1405 + +2009-02-12 11:48 jeff + + * FS/FS/: cust_tax_location.pm, tax_rate.pm: proper match arguments + help + +2009-02-12 07:55 jeff + + * httemplate/: misc/tax-import.cgi, elements/form-file_upload.html: + better upload error handling and correction of tax upload + filecount + +2009-02-11 10:44 ivan + + * httemplate/search/cdr.html: fix select and unselect all buttons + on CDR bulk actions, RT#4766 + +2009-02-11 08:06 jeff + + * FS/FS/Schema.pm: mac is unique + +2009-02-10 08:25 jeff + + * httemplate/edit/part_pkg.cgi: fix taxproduct fallout from IE 2083 + limit workaround + +2009-02-10 02:35 ivan + + * FS/FS/AccessRight.pm, httemplate/misc/cdr.cgi, + httemplate/search/cdr.html: quick n' dirty CDR deletion from web + interface, RT#4766 / RT#4731 + +2009-02-09 07:03 ivan + + * httemplate/browse/agent.cgi: try for slightly better UI on agent + config overrides + +2009-02-09 06:05 ivan + + * FS/FS/Conf.pm, FS/FS/cust_bill.pm, FS/FS/cust_credit.pm, + FS/FS/cust_pay.pm, FS/bin/freeside-expiration-alerter, + conf/invoice_html, conf/invoice_html_statement, + httemplate/config/config-image.cgi, + httemplate/config/config-process.cgi, + httemplate/config/config-view.cgi, httemplate/config/config.cgi, + httemplate/elements/header.html, httemplate/view/REAL_logo.cgi, + httemplate/view/cust_bill-logo.cgi: rest of per-agent config for + company_name, company_address, logo, etc.. RT#3989 + +2009-02-09 03:45 ivan + + * FS/FS/UI/Web.pm: pull out the data for address fields too! + RT#4583 + +2009-02-09 03:35 ivan + + * FS/FS/ConfDefaults.pm: more consistent labeling, RT#4583 + +2009-02-09 03:32 ivan + + * FS/FS/: UI/Web.pm, ConfDefaults.pm: add some more customer output + formats that include service address, RT#4583 + +2009-02-09 02:38 ivan + + * FS/bin/freeside-fetch: increase LWP timeout, some reports can + take a while + +2009-02-08 21:59 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add skip_dcontext and + skip_dstchannel_prefix options, RT#3196 + +2009-02-08 17:49 ivan + + * FS/FS/access_user.pm, FS/FS/part_pkg.pm, + httemplate/browse/access_group.html, + httemplate/browse/part_pkg.cgi, httemplate/edit/part_pkg.cgi, + httemplate/edit/elements/edit.html, + httemplate/elements/select-part_pkg.html: further work on agents + editing own packages: fix fallout on package customization from + turning agent_virt on in edit/part_pkg.cgi, add a "clone package" + to package browse, like clone service, and have agent type + selection disappear when you set an agentnum. RT#1331 + +2009-02-07 18:05 ivan + + * FS/FS/access_user.pm, FS/FS/cust_pkg.pm, + httemplate/browse/part_pkg.cgi, httemplate/edit/cust_main.cgi, + httemplate/edit/part_pkg.cgi, httemplate/edit/elements/edit.html, + httemplate/edit/process/part_pkg.cgi, + httemplate/elements/select-agent_types.html, + httemplate/elements/select-cust-part_pkg.html, + httemplate/elements/select-part_pkg.html, + httemplate/elements/select-table.html, + httemplate/elements/tr-select-agent_types.html, + httemplate/search/elements/search.html, + FS/FS/ClientAPI/Signup.pm: further work on agents editing own + packages: allow them to see (but not edit) global packages for + their type, RT#1331 + +2009-02-07 12:16 ivan + + * FS/FS/ClientAPI/MyAccount.pm, + fs_selfservice/FS-SelfService/SelfService.pm: add more + documentation on order_pkg and the ability to order svc_phone + too, RT#4722 + +2009-02-07 11:35 ivan + + * httemplate/view/cust_main/payment_history.html: right-align + amount in prev history row + +2009-02-07 11:34 ivan + + * FS/FS/Record.pm: don't look up encryption config every search, + this should help perf a lot with database config in 1.9 + +2009-02-07 11:05 ivan + + * bin/pod2x: no, it doesn't look like we have query + +2009-02-07 00:23 ivan + + * httemplate/view/cust_main/: payment_history.html, packages.html, + packages/location.html, packages/services.html, + packages/status.html, payment_history/payment.html, + payment_history/refund.html: optimize customer view: avoid + looking up config values inside loops, RT#4728 + +2009-02-06 17:45 ivan + + * fs_selfservice/FS-SelfService/SelfService.pm: fix up POD + formatting, RT#4727 + +2009-02-06 17:33 ivan + + * bin/pod2x: don't need this + +2009-02-06 17:26 ivan + + * bin/pod2x: update pod2x to use Mediawiki module instead of + WWW:::Mediawiki::Client. whew, that wasn't so bad. RT#4727 + +2009-02-06 10:31 ivan + + * httemplate/elements/location.html: fix spurious "Unit #" label + showing up, RT#4745 + +2009-02-05 13:02 jeff + + * FS/FS/tax_rate.pm: pluralization agreement + +2009-02-05 08:57 jeff + + * FS/FS/: Conf.pm, tax_rate.pm: add a config flag to ignore new + style taxes instead of throwing fatal errors + +2009-02-04 07:58 jeff + + * FS/FS/cust_main.pm: with usage classes, the probability of a + taxless line item tranche is too high for this to be a fatal + error. we risk overlooking misconfigured taxes/packages + +2009-02-03 13:33 jeff + + * FS/FS/part_pkg.pm: the taxproductnum is ALWAYS one of the + filtering conditions + +2009-02-01 05:52 ivan + + * bin/test_scrub: adding scrub tool + +2009-02-01 04:48 ivan + + * httemplate/elements/menu.html: yow, don't hide the config menu + unnecessarily + +2009-02-01 04:28 ivan + + * fs_selfservice/FS-SelfService/cgi/: ach_payment_results.html, + agent_delete_svc.html, agent_main.html, agent_order_pkg.html, + agent_provision.html, agent_provision_svc_acct.html, + change_bill.html, change_password.html, change_pay.html, + change_ship.html, customer_change_pkg.html, + customer_order_pkg.html, delete_svc.html, footer.html, + list_customers.html, make_ach_payment.html, make_payment.html, + myaccount.html, payment_results.html, process_change_bill.html, + process_change_password.html, process_change_pay.html, + process_change_pkg.html, process_change_ship.html, + process_order_pkg.html, process_order_recharge.html, + process_svc_acct.html, process_svc_external.html, provision.html, + provision_svc_acct.html, recharge_prepay.html, + recharge_results.html, selfservice.cgi, view_customer.html, + view_invoice.html, view_support_details.html, view_usage.html, + view_usage_details.html: put the footer in one frigging file, + whew + +2009-02-01 02:37 ivan + + * FS/FS/Schema.pm: indexing cust_bill_event.eventpart should help + speed up freeside-migrate-events slightly... RT#4277 + +2009-01-31 20:13 ivan + + * FS/FS/Upgrade.pm: commit after each table upgrade, helps with + getting huge dbs upgraded, RT#4679 + +2009-01-31 01:53 ivan + + * FS/FS/access_user.pm: cache the results of ACL queries, should + improve performance of customer view page for customers with + shitloads of packages/services, RT#4696 + +2009-01-30 12:44 ivan + + * FS/FS/ClientAPI_SessionCache.pm: should use FS::Conf + +2009-01-29 16:40 ivan + + * FS/FS/UI/bytecount.pm: we're not a disk drive manufacturer + +2009-01-29 11:21 ivan + + * FS/FS/cust_pkg.pm: fix unsuspend-always_adjust_next_bill_date + config, RT#4271 + +2009-01-28 08:29 rsiddall + + * rpm/freeside.spec: Removed conflict between core billing package + and self-service RPMs so you can install them all on the same + machine. This may have applications if you're using XMLRPC to + talk to the self-service interface from PHP, Python, etc. + +2009-01-27 01:39 ivan + + * FS/FS/AccessRight.pm, httemplate/search/elements/search.html: add + ACL to allow download of browse/ stuff too, when possible. + RT#4681 + +2009-01-25 20:22 ivan + + * FS/FS/cust_main.pm: i think this was right after all, we do want + to look for a county-less state+country match before country only + and giving up, RT#4681 + +2009-01-25 18:14 ivan + + * FS/FS/cust_bill.pm: should fix: Argument "\\dollar 2.69" isn't + numeric in sprintf at /usr/local/share/perl/5.8.8/FS/cust_bill.pm + line 2193. Hopefully no problems with invoice with 0 tax + printing :/. RT#4681 + +2009-01-25 17:36 ivan + + * FS/FS/cust_main.pm: should be better error message for inability + to find tax rates, RT#4681. also pull in the add_freq changes. + *think* they're safe. famous last words. + +2009-01-25 17:07 ivan + + * FS/FS/cust_pkg.pm: fix harmless warning, RT#4681: Argument "" + isn't numeric in numeric eq (==) at + /usr/local/share/perl/5.8.8/FS/cust_pkg.pm line 443. + +2009-01-25 15:58 ivan + + * FS/FS/Record.pm, FS/FS/part_pkg.pm, httemplate/edit/part_pkg.cgi, + httemplate/edit/elements/edit.html: fix one-time charges and + package customization for employees who don't have 'Edit global + package definition' ACL, RT#4668 + +2009-01-25 14:20 ivan + + * httemplate/browse/: access_group.html, access_user.html: + normalize terminology: s/internal users/employees/ + +2009-01-25 12:43 ivan + + * FS/bin/: freeside-cdrd, freeside-queued: reduce waiting time for + -cdrd and -queued, RT#4667 + +2009-01-24 17:27 ivan + + * FS/FS/cust_svc.pm: add some debugging to RADIUS db calls + +2009-01-24 13:53 ivan + + * fs_selfservice/php/: order_renew.php, + process_payment_order_renew.php: finish up prepay example, + RT#4623 + +2009-01-24 13:53 ivan + + * FS/FS/ClientAPI/MyAccount.pm: have the prepay amounts include the + current balance, RT#4623 + +2009-01-24 13:49 ivan + + * httemplate/edit/cust_main.cgi: wtf, don't pop up the geocode + chooser when taxproducts are off + +2009-01-24 13:04 ivan + + * httemplate/: elements/select-domain.html, + elements/select-table.html, elements/tr-select-domain.html, + search/report_svc_acct.html, search/svc_acct.cgi: add domain + selection to advanced account report (side effect on RT#4623) + +2009-01-22 17:23 ivan + + * fs_selfservice/php/: freeside.class.php, login.php, main.php, + order_renew.php, process_login.php, + process_payment_order_renew.php: add the start at PHP + self-service as a quick early renew example + +2009-01-22 16:49 ivan + + * FS/FS/ClientAPI/MyAccount.pm: typo in rounding the amounts + returned by renew_info, RT#4623 + +2009-01-22 16:23 ivan + + * FS/FS/ClientAPI/MyAccount.pm: round the amounts returned by + renew_info, RT#4623 + +2009-01-22 09:29 ivan + + * FS/FS/part_pkg.pm, FS/FS/ClientAPI/MyAccount.pm, + fs_selfservice/FS-SelfService/SelfService.pm: add self-service + methods renew_info, order_renew and process_payment_order_renew + to enable self-renewal through self-service. RT#4623 + +2009-01-20 18:02 ivan + + * httemplate/edit/: part_pkg.cgi, elements/edit.html: fix + (hopefully last of the) customize package bogosity in 1.9, + RT#4662 + +2009-01-20 16:52 ivan + + * FS/FS/cust_bill_pkg_tax_location.pm: stupid typo preventing + service addresses from working, RT#4663 + +2009-01-20 12:08 ivan + + * FS/FS/: cust_main.pm: whew, hopefully that will actually fix + agent-specific invoices migrated from 1.7->1.9, RT#4645 + +2009-01-20 11:35 ivan + + * FS/FS/cust_bill.pm: fix agent-specific logos migrated from 1.7, + RT#4645 + +2009-01-19 15:53 ivan + + * FS/FS/tax_rate.pm, httemplate/misc/process/tax-import.cgi: + tax-pkg_location changes broke new taxation, this should fix + +2009-01-19 15:44 ivan + + * FS/FS/part_pkg/voip_cdr.pm: turn debugging off + +2009-01-19 14:32 ivan + + * FS/FS/part_pkg/voip_cdr.pm: don't ignore the cdrtypenum rule for + 0, hopefully finally fix DA for QIS, RT#4502 + +2009-01-19 09:37 ivan + + * httemplate/edit/process/cust_pkg.cgi: fix error on bulk package + order/cancel, RT#4645 + +2009-01-18 22:36 ivan + + * httemplate/: elements/tr-select-cust_location.html, + view/cust_main/packages/location.html: default service location + is cust_main ship_ address when present! RT#4499 + +2009-01-18 19:50 ivan + + * FS/FS/Schema.pm, FS/FS/rate.pm, + httemplate/edit/process/rate_region.cgi: 10 digit prefix + matching, RT#4403 + +2009-01-18 15:51 ivan + + * FS/FS/cust_pkg.pm: finish package location tax reporing, RT#4499 + +2009-01-18 15:43 ivan + + * FS/MANIFEST, FS/FS/Schema.pm, FS/FS/cust_bill_pkg.pm, + FS/FS/cust_bill_pkg_tax_location.pm, FS/FS/cust_main.pm, + FS/FS/cust_main_county.pm, FS/FS/tax_rate.pm, + FS/t/cust_bill_pkg_tax_location.t, + httemplate/search/cust_bill_pkg.cgi, + httemplate/search/report_tax.cgi, + httemplate/view/cust_main/packages/location.html: finish package + location tax reporing, RT#4499 + +2009-01-18 13:06 rsiddall + + * rpm/freeside.sysconfig: bash didn't like spaces on each side of + an equals sign. + +2009-01-13 05:00 ivan + + * FS/FS/part_export/internal_diddb.pm: fix internal_diddb delete & + return number to availability, RT#4603 + +2009-01-12 19:25 ivan + + * FS/FS/part_pkg/voip_cdr.pm: whew, works fine, rewrite to 411 was + sticky that's why calls were being skipped for wrong carrierid, + RT#4502 + +2009-01-12 18:39 ivan + + * FS/FS/part_pkg/voip_cdr.pm: by his noodly appendage, i hope this + is just a precendece problem, RT#4502 + +2009-01-12 18:13 ivan + + * FS/FS/part_pkg/voip_cdr.pm: WORKING avoid looking up options + inside the rating loop, RT#4502 + +2009-01-12 17:58 ivan + + * FS/FS/part_pkg/voip_cdr.pm: avoid looking up options inside the + rating loop, RT#4502 + +2009-01-12 17:34 ivan + + * FS/FS/part_pkg/voip_cdr.pm: refactor out the ignoring rules into + check_chargable; ignore carrierid rule w/411 rewrite, RT#4502 + +2009-01-12 16:17 ivan + + * FS/FS/part_pkg/voip_cdr.pm: wtf is up with 411_rewrite, RT#4502 + +2009-01-12 15:51 ivan + + * FS/FS/: Conf.pm, Record.pm, cdr/taqua.pm: taqua config to rewrite + DA calls, RT#4502 + +2009-01-12 13:16 jeff + + * FS/FS/cust_main.pm: tickets only exist when a ticket system + exists + +2009-01-12 12:59 jeff + + * FS/FS/cust_main.pm: doc tyop + +2009-01-12 01:01 jeff + + * FS/FS/svc_acct.pm: vfw callback failure + +2009-01-10 15:56 ivan + + * FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/cust_main.pm, + FS/FS/cust_pkg.pm, httemplate/misc/change_pkg.cgi, + httemplate/edit/process/change-cust_pkg.html, + httemplate/edit/process/cust_pkg.cgi, + httemplate/elements/location.html, + httemplate/elements/tr-select-cust_location.html, + httemplate/view/cust_main/packages/location.html, + httemplate/view/cust_main/packages/package.html: implement + package changes w/location change, RT#4499 + +2009-01-09 16:43 ivan + + * FS/FS/Conf.pm, FS/FS/cust_main.pm, FS/FS/cust_pkg.pm, + httemplate/elements/location.html, + httemplate/elements/tr-select-cust_location.html, + httemplate/view/cust_main/packages.html, + httemplate/edit/process/quick-cust_pkg.cgi, + httemplate/misc/location.cgi, httemplate/misc/order_pkg.html: + more work on package service addresses: hide locations when + they're all the default, config to show them anyway / finish + implementing package ordering, fix all the state/county weirdness + when changing the location dropdown. RT#4499 + +2009-01-08 20:06 ivan + + * httemplate/edit/cust_main/contact.html, + httemplate/elements/location.html, + httemplate/elements/select-country.html, + httemplate/elements/select-county.html, + httemplate/elements/select-state.html, + httemplate/elements/tr-select-part_referral.html, + httemplate/misc/location.cgi, httemplate/misc/order_pkg.html, + FS/FS/Mason.pm, FS/FS/cust_location.pm, FS/FS/cust_main.pm, + httemplate/view/cust_main/packages.html, + httemplate/view/cust_main/packages/location.html: pick/enter a + location when ordering a package, RT#4499 + +2009-01-07 17:45 ivan + + * FS/FS.pm, FS/MANIFEST, FS/FS/Conf.pm, FS/FS/Schema.pm, + FS/FS/cust_location.pm, FS/FS/cust_main.pm, FS/FS/cust_pkg.pm, + FS/t/cust_location.t, eg/table_template.pm, + eg/table_template-svc.pm, + httemplate/view/cust_main/packages.html, + httemplate/view/cust_main/packages/location.html, + httemplate/view/cust_main/packages/package.html, + httemplate/view/cust_main/packages/services.html, + httemplate/view/cust_main/packages/status.html: start adding + package locations, RT#4499 + +2009-01-07 08:59 jeff + + * conf/invoice_latex: allow tex to do more column sizing + +2009-01-06 16:27 ivan + + * httemplate/browse/rate_region.html: country code is two words + +2009-01-06 16:18 ivan + + * FS/FS/part_pkg/voip_cdr.pm: fixup error message, this is all for + RT#4524 + +2009-01-06 16:14 ivan + + * httemplate/browse/: rate.cgi, rate_region.html: add a dropdown to + help browse regions by countrycode + +2009-01-06 15:30 ivan + + * FS/FS/part_pkg/voip_cdr.pm: throw a fatal error if a call is + unrateable and add an ignore_unrateable flag to go back to the + old skip behavior + +2009-01-06 13:16 ivan + + * FS/FS/: cdr.pm, part_pkg/voip_cdr.pm: swap price to last column + in default CDR output format; fix "all 0 prices" when using + simple output format w/internal rating, RT#4503 + +2009-01-05 13:12 jeff + + * FS/FS/tax_rate.pm: doh! change the interface here, too + +2009-01-04 16:26 ivan + + * httemplate/elements/checkboxes-table-name.html, + httemplate/elements/checkboxes.html, + httemplate/elements/select-rate.html, + httemplate/elements/tr-select-rate.html, FS/FS/rate_prefix.pm, + httemplate/browse/rate.cgi, + httemplate/misc/copy-rate_detail.html, + httemplate/misc/process/copy-rate_detail.html: add rate copying, + RT#4431 + +2009-01-04 14:07 ivan + + * Makefile, init.d/freeside-init: don't run a self-service server + against localhost OOTB; eliminate those gigantic useless logfiles + +2009-01-02 17:52 ivan + + * bin/cdr.http_and_import, bin/cdr.import, bin/cdr.sftp_and_import, + FS/FS/Record.pm, FS/FS/cdr.pm, FS/FS/cdr/indosoft.pm: indosoft + CDR format, RT#4425 + +2009-01-02 14:03 ivan + + * FS/FS/Record.pm, FS/FS/cdr.pm, FS/FS/cdr/bell_west.pm, + FS/FS/cdr/troop.pm, bin/cdr.import, bin/cdr.sftp_and_import: add + troop CDRs, RT#4413 + +2009-01-02 10:01 ivan + + * eg/cdr_template.pm: cdr template, RT#4413 and RT#4412 + +2009-01-02 09:58 ivan + + * FS/FS/cdr/troop.pm: commiting initial troop CDR template, RT#4413 + +2009-01-01 12:11 rsiddall + + * rpm/freeside-selfservice.conf: New Apache configuration file for + the self-service interface. + +2009-01-01 12:10 rsiddall + + * rpm/freeside.spec: Modifications to let self-service work if you + really insist on installing it on the same machine as the billing + server. Also more fixes for SuSE, and a couple of changes to + minimize differences from the 1.7 branch. + +2008-12-31 14:04 ivan + + * FS/FS/: Record.pm, cdr/bell_west.pm: finish up working bell_west + CDR format, RT#4403 + +2008-12-31 10:07 jeff + + * FS/FS/cust_main.pm: one got missed? + +2008-12-30 19:28 ivan + + * FS/FS/Record.pm, FS/FS/cdr.pm, FS/FS/phone_avail.pm, + FS/FS/cdr/bell_west.pm, FS/FS/cdr/simple.pm, + FS/FS/part_pkg/voip_cdr.pm, httemplate/edit/rate_detail.html, + httemplate/misc/cdr-import.html, + httemplate/misc/process/cdr-import.html: bell west CDR format, + RT#4403 + +2008-12-30 14:00 jeff + + * FS/FS/: cust_pkg.pm, cust_pkg_reason.pm: yet more timestamping + improvements and corrections to reasons based on history records + +2008-12-30 13:45 jeff + + * FS/FS/cdr.pm: move price to last column for default_source + +2008-12-30 11:13 jeff + + * FS/FS/part_pkg/voip_cdr.pm: allow upstream_simple to specify a + usage_class for tax purposes in calltypenum + +2008-12-29 10:06 jeff + + * Makefile, conf/invoice_latex, conf/longtable.sty.patch, + etc/fslongtable.sty: ease deployment of patched longtable + +2008-12-28 11:10 ivan + + * httemplate/browse/cust_main_county.cgi: finish dealing with + counties with spaces, etc., RT#4496 + +2008-12-28 11:08 ivan + + * httemplate/edit/process/cust_main_county-expand.cgi: allow normal + ut_textn strings in county expansion, RT#4496 + +2008-12-28 10:59 ivan + + * httemplate/browse/cust_main_county.cgi: deal with counties with + spaces, etc., RT#4496 + +2008-12-28 10:52 ivan + + * httemplate/browse/cust_main_county.cgi: put the + country/state/county selections on their own line, RT#4496 + +2008-12-28 10:48 ivan + + * httemplate/elements/: select-country.html, select-county.html, + select-state.html, select-did.html: fix browse results for + selecting counties (resulting from separating tax classes), also + add dropdowns to browse by state and county, RT#4496 + +2008-12-28 10:44 ivan + + * httemplate/: browse/cust_main_county.cgi, + edit/cust_main/contact.html, edit/cust_main/billing.html, + misc/payment.cgi, edit/cust_main/select-country.html, + edit/cust_main/select-county.html, + edit/cust_main/select-state.html: fix browse results for + selecting counties (resulting from separating tax classes), also + add dropdowns to browse by state and county, RT#4496 + +2008-12-24 16:45 jeff + + * FS/FS/: cust_bill_pkg.pm, cust_main.pm, cust_main_county.pm: fix + "texas tax" in 1.9 + +2008-12-23 13:41 jeff + + * FS/FS/cust_main.pm: miss use + +2008-12-23 12:35 jeff + + * FS/FS/cust_main.pm: correct bad tax calculation + +2008-12-22 16:32 ivan + + * FS/FS/: cust_bill.pm: truncate package descriptions over 50 chars + to avoid pushing the total column out to the right, RT#4449 + +2008-12-22 15:28 ivan + + * httemplate/config/config.cgi: textareas are much less annoying to + work with when their scrollbar isn't scrolled off the side itself + +2008-12-22 14:30 rsiddall + + * rpm/freeside.spec: Copying over modifications to support SuSE + from the 1.7 branch. + +2008-12-22 13:16 ivan + + * httemplate/edit/: part_pkg.cgi, quick-charge.html: soft-limit + package names to 50 chars to avoid problems with typeset + invoices, RT#4449 + +2008-12-21 13:53 ivan + + * FS/FS/svc_phone.pm: and fix msgcat usage, this should do it?, + RT#4204 + +2008-12-21 13:49 ivan + + * FS/FS/svc_acct.pm: svc_acct.pm bogosity too, wtf?!, RT#4204 + +2008-12-21 13:44 ivan + + * FS/FS/: msgcat.pm: msgcat.pm upgrade bogosity, shrug, RT#4204 + +2008-12-21 13:37 ivan + + * FS/FS/: svc_Common.pm, Upgrade.pm: unique checking for svc_phone + like svc_acct, closes: RT#4204 (also a few lines of the new + per-agent config snuck in Conf.pm from RT#3989) + +2008-12-21 13:33 ivan + + * FS/: FS/svc_phone.pm, FS/Conf.pm, FS/Record.pm, FS/Setup.pm, + FS/msgcat.pm, FS/svc_Common.pm, FS/svc_acct.pm, + bin/freeside-upgrade: unique checking for svc_phone like + svc_acct, closes: RT#4204 (also a few lines of the new per-agent + config snuck in Conf.pm from RT#3989) + +2008-12-21 10:38 ivan + + * FS/bin/freeside-cdrd: cdrd brainfart, finishing up RT#4423 + +2008-12-21 10:09 ivan + + * FS/: FS/Schema.pm, FS/queue.pm, bin/freeside-cdrd: have + freeside-queued put billing jobs in the queue, so they run in + their own short-lived processes, RT#4423 + +2008-12-21 09:40 ivan + + * FS/FS/queue.pm: doc + +2008-12-15 16:08 jeff + + * FS/FS/cust_pkg.pm: proper dates on expire and suspend reasons + +2008-12-11 13:11 jeff + + * FS/FS/cust_main.pm: place tax on invoice only once + +2008-12-10 13:43 ivan + + * httemplate/search/: cust_bill_event.html, report_cust_bill.html, + report_cust_credit.html, report_cust_event.html, + report_cust_main-zip.html, report_cust_main.html, + report_cust_pay.html, report_cust_pay_batch.html, + report_cust_pkg.html, report_newtax.html, report_svc_acct.html, + report_tax.html: allow all-agent reporting again + +2008-12-10 13:33 ivan + + * httemplate/graph/: report_cust_bill_pkg.html, + report_cust_pkg.html, report_money_time.html: allow all-agent + reporting again + +2008-12-10 12:20 ivan + + * FS/FS/cust_main/Import.pm: referral import fixes, RT#4427 + +2008-12-10 11:43 rsiddall + + * rpm/freeside.spec: Cleanup to quieten rpmlint. Fixes to cope + with moving code out of handler.pl, etc. + +2008-12-10 11:42 rsiddall + + * rpm/rpm2Bundle: Further modifications to handle Perl RPM names + and map them back to Perl module names. + +2008-12-09 18:47 jeff + + * FS/FS/cust_tax_location.pm: space is empty + +2008-12-08 17:49 ivan + + * FS/FS/Record.pm: oops + +2008-12-08 17:46 ivan + + * FS/FS/Record.pm, FS/FS/inventory_item.pm, + httemplate/misc/inventory_item-import.html, + httemplate/misc/process/inventory_item-import.html: use common + base for inventory import too, fixes problems with errors due to + dos line endings and allows Excel upload, RT#4346 + +2008-12-08 02:13 ivan + + * FS/FS/cust_bill_pkg.pm: make CDRs smaller, so we can fit more + columns, RT#4376 + +2008-12-08 01:08 ivan + + * FS/FS/Schema.pm: make room for CDRs, RT#4387 + +2008-12-08 00:52 ivan + + * FS/FS/: cdr.pm, part_pkg/voip_cdr.pm: respect output_format and + add an header for rating_method=prefix too, RT#4387 + +2008-12-08 00:46 ivan + + * conf/invoice_html: normal ext_desc shouldn't shove the second+ + columns of CDRs out + +2008-12-05 09:23 jeff + + * FS/FS/tax_rate.pm: passthrough support for gross revenue taxes + +2008-12-05 09:19 jeff + + * FS/FS/part_pkg.pm: avoid taxation on products with no assigned + taxes + +2008-12-05 00:24 jeff + + * FS/FS/cust_main.pm: missing uses, corrects 4388 + +2008-12-04 20:20 jeff + + * FS/FS/cust_main_county.pm: bad shortcut causes taxes not to be + charged + +2008-12-03 21:16 jeff + + * FS/FS/part_export/soma.pm: wtf? + +2008-12-03 18:19 jeff + + * httemplate/edit/cust_main.cgi: better placement of script + sourcing + +2008-12-03 18:03 jeff + + * httemplate/elements/init_overlib.html: better placement of script + sourcing + +2008-12-03 17:46 jeff + + * httemplate/edit/cust_main/choose_tax_location.html: better + behavior when zip code is missing + +2008-12-03 15:29 ivan + + * httemplate/search/report_receivables.html: allow an all-agent + receivables report again + +2008-12-03 13:15 ivan + + * httemplate/misc/whois.cgi: fix real customer numbers showing on + view pages, RT#4099/4379 + +2008-12-03 13:12 ivan + + * httemplate/view/: cust_pay.html, cust_refund.html, cust_bill.cgi, + svc_broadband.cgi, svc_domain.cgi, svc_external.cgi, + svc_forward.cgi, svc_www.cgi: fix real customer numbers showing + on view pages, RT#4099/4379 + +2008-12-03 09:25 ivan + + * FS/FS/part_export/internal_diddb.pm: fix internal_diddb to + default to countrycode 1 + +2008-12-02 21:53 ivan + + * httemplate/edit/: part_pkg.cgi, elements/edit.html: 60 char soft + max length for packages, so invoices don't wrap, RT#4328 + +2008-12-02 17:42 jeff + + * bin/import-tax-rates, + httemplate/edit/cust_main/choose_tax_location.html, + httemplate/edit/cust_main/contact.html, + httemplate/elements/ajaxcontentmws.js, FS/FS/Misc.pm, + FS/FS/Schema.pm, FS/FS/cust_main.pm, FS/FS/cust_tax_location.pm, + FS/FS/part_pkg_taxrate.pm, FS/FS/tax_class.pm, FS/FS/tax_rate.pm, + httemplate/edit/cust_main.cgi, httemplate/misc/tax-import.cgi, + httemplate/misc/xmlhttp-cust_main-address_standardize.html: + support zip5 tax lookups, correct errors with fixed format cch + import, inital import performance improvements, noise reduction + on imports, tool for inital import + +2008-11-30 23:52 ivan + + * FS/FS/: Conf.pm, cdr.pm: set charged_party to accoutncode for + vedeye, RT#4342 + +2008-11-30 15:37 ivan + + * httemplate/edit/access_user.html: s/Internal Access + Groups/Employee Groups/ + +2008-11-30 15:34 ivan + + * httemplate/: browse/access_user.html, edit/access_user.html: + s/Internal Users/Employees/ + +2008-11-30 15:26 ivan + + * httemplate/: browse/access_group.html, edit/access_group.html: + s/Internal Access Groups/Employee Groups/ + +2008-11-30 13:01 ivan + + * FS/FS/cdr.pm: _cdr_min_parser_maker fix for correct setting of + duration/billsec with simple & simple2 rate plans + +2008-11-29 13:54 ivan + + * FS/FS/ClientAPI/MyAccount.pm, FS/FS/svc_phone.pm, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/cgi/login.html, + fs_selfservice/FS-SelfService/cgi/selfservice.cgi: add + selfservice_server-single_domain config, and login_info + self-service method to give the login page a bit more + configurability + +2008-11-29 12:32 ivan + + * FS/FS/Conf.pm: add selfservice_server-single_domain config, and + login_info self-service method to give the login page a bit more + configurability + +2008-11-25 16:30 ivan + + * FS/FS/ClientAPI/PrepaidPhone.pm: don't set a Session-Timeout if + the rate is 0 + +2008-11-25 16:20 ivan + + * FS/FS/: Record.pm, cust_main/Import.pm: should fix importing from + excel, closes: RT#4337 + +2008-11-24 07:40 jeff + + * FS/FS/part_export/soma.pm: more caffiene, please + +2008-11-24 07:36 jeff + + * FS/FS/part_export/soma.pm: doh + +2008-11-24 07:18 jeff + + * FS/FS/part_export/soma.pm: be more accepting + +2008-11-24 06:48 jeff + + * FS/FS/part_export/soma.pm: esn's are hex + +2008-11-24 04:22 ivan + + * FS/FS/cdr/genband.pm: update genband import to agree with + reality, RT#4177 + +2008-11-24 02:59 ivan + + * FS/FS/part_export/internal_diddb.pm: add countrycode option to + internal_diddb; throw a warning instead of an error if a number + couldn't be returned to inventory + +2008-11-24 02:47 ivan + + * FS/FS/part_export/: phone_sqlradius.pm, sqlradius.pm: fix + phone_sqlradius CDR population?, RT#4100 + +2008-11-24 02:11 ivan + + * FS/FS/ClientAPI/PrepaidPhone.pm: add debugging, hopefully fix + seconds returned finally, RT#4100 + +2008-11-24 00:47 ivan + + * FS/FS/ClientAPI/PrepaidPhone.pm: look for a voip rate in pricing + add-ons too... eek. also correct rating to destination RT#4100 + +2008-11-22 14:17 ivan + + * FS/FS/: Conf.pm, Schema.pm, cust_credit.pm, cust_main.pm, + cust_pkg.pm, part_event.pm, part_event/Action/addpost.pm, + part_event/Condition.pm, part_event/Action/apply.pm, + part_event/Action/bill.pm, part_event/Action/cancel.pm, + part_event/Action/collect.pm, + part_event/Action/cust_bill_batch.pm, + part_event/Action/cust_bill_comp.pm, + part_event/Action/cust_bill_fee_percent.pm, + part_event/Action/cust_bill_realtime_card.pm, + part_event/Action/cust_bill_realtime_check.pm, + part_event/Action/cust_bill_realtime_lec.pm, + part_event/Action/cust_bill_send.pm, + part_event/Action/cust_bill_send_agent.pm, + part_event/Action/cust_bill_send_alternate.pm, + part_event/Action/cust_bill_send_csv_ftp.pm, + part_event/Action/cust_bill_send_if_newest.pm, + part_event/Action/cust_bill_spool_csv.pm, + part_event/Action/cust_bill_suspend_if_balance.pm, + part_event/Action/fee.pm, + part_event/Action/pkg_referral_credit.pm, + part_event/Action/pkg_referral_credit_pkg.pm, + part_event/Action/suspend.pm, + part_event/Action/suspend_if_pkgpart.pm, + part_event/Action/suspend_unless_pkgpart.pm, + part_event/Condition/balance.pm, + part_event/Condition/balance_age.pm, + part_event/Condition/balance_under.pm, + part_event/Condition/cust_bill_age.pm, + part_event/Condition/cust_bill_has_service.pm, + part_event/Condition/cust_bill_owed.pm, + part_event/Condition/cust_bill_owed_under.pm, + part_event/Condition/cust_payments.pm, + part_event/Condition/has_referral_custnum.pm, + part_event/Condition/once_percust.pm, + part_event/Condition/pkg_age.pm, + part_event/Condition/pkg_notchange.pm, + part_event/Condition/pkg_pkgpart.pm, + part_event/Condition/pkg_recurring.pm, + part_event/Condition/pkg_unless_pkgpart.pm, part_pkg/flat.pm: + referral credits overhaul, use billing events, agents can + self-configure, limit to once-per-customer, depend on any time + from referred package, referred customer payment, specific + packages, partial staged credits, RT#3983 + +2008-11-21 23:10 ivan + + * httemplate/: browse/part_event.html, edit/elements/edit.html: + billing event cloning + +2008-11-20 19:36 jeff + + * FS/FS/part_export/soma.pm: initial somanetworks support + +2008-11-20 18:57 ivan + + * httemplate/edit/elements/edit.html: remove debugging accidentally + left in + +2008-11-20 18:55 ivan + + * httemplate/edit/process/elements/process.html: document + viewall_ext + +2008-11-20 17:58 ivan + + * httemplate/: edit/elements/edit.html, + elements/tr-select-agent.html: undo voodoo, find real problem + +2008-11-20 16:06 ivan + + * httemplate/edit/elements/edit.html: voodoo + +2008-11-20 11:02 jeff + + * FS/FS/rate.pm: this must be what is meant + +2008-11-20 09:49 jeff + + * FS/bin/freeside-dedup-cust_bill_pkg_detail-header: tool to remove + extra cdr headers + +2008-11-20 08:59 jeff + + * FS/FS/part_pkg/voip_cdr.pm: only one header per package, not one + per service -- fixes #4260 + +2008-11-20 04:52 ivan + + * FS/FS/cust_main/Import.pm: better end-of-spreadsheet detection + for excel import, hopefully. should fix "Error: Can't use an + undefined value as an ARRAY reference" error on import. RT#4297 + +2008-11-20 03:35 ivan + + * bin/rate.delete: fill in the ratenum. doesn't actually delete + the rate itself, just all its data (the hard part) + +2008-11-19 16:42 ivan + + * FS/FS/cust_bill.pm: don't use payname for CARD or DCRD either, + closes: RT#3982 + +2008-11-19 06:55 jeff + + * FS/FS/Misc.pm, FS/FS/Schema.pm, FS/FS/cust_tax_location.pm, + FS/FS/part_pkg_taxrate.pm, FS/FS/tax_class.pm, FS/FS/tax_rate.pm, + httemplate/misc/tax-import.cgi: support for cch fixed format + +2008-11-18 17:24 ivan + + * FS/FS/Schema.pm: fix phone_avail.availnum to be a proper primary + key, fix agent.agent_custnum unique index causing it to get a + value filled in by Record.pm + +2008-11-17 18:56 rsiddall + + * rpm/rpm2Bundle: Now handles hyphenated Perl requirements as well + as those in parentheses, and handles more version relation types. + +2008-11-12 18:22 ivan + + * FS/FS/access_groupagent.pm, FS/FS/agent.pm, + httemplate/browse/agent.cgi, httemplate/edit/agent.cgi, + httemplate/edit/process/agent.cgi: add ability to view/edit + access groups of an agent + +2008-11-11 00:55 ivan + + * FS/FS/cust_bill.pm: add fax to invoice data, RT#3290 + +2008-11-11 00:45 ivan + + * conf/: invoice_html, invoice_latex: agent_custid and ship_fax + don't belong with the ship address, that was an unrelated + tampabay/pbx-change request, RT#3290 + +2008-11-10 23:51 ivan + + * conf/invoice_html: make HTML invoice more consistent with current + typeset invoice: center invoice date instead of right-justify + +2008-11-09 03:43 ivan + + * httemplate/browse/agent.cgi: realign things in light of + small_custview in this table for master customering, roundaboutly + part of #2933 + +2008-11-09 03:31 ivan + + * FS/FS/cust_main/Import.pm: move batch customer import to its own + file; add svc_external_svc_phone export format, RT#4103 + +2008-11-09 01:14 ivan + + * FS/FS/Conf.pm, httemplate/elements/file-upload.html, + httemplate/misc/phone_avail-import.html: add a global countrycode + to phone_avail import and a conf for the default (some other conf + values snuck in also, oh well) + +2008-11-09 00:51 ivan + + * FS/FS/Mason.pm, FS/FS/cust_main.pm, FS/FS/part_pkg.pm, + FS/FS/cust_main/Import.pm, httemplate/misc/cust_main-import.cgi, + Makefile, FS/FS.pm, FS/MANIFEST, FS/bin/freeside-queued, + httemplate/misc/process/cust_main-import.cgi: move batch customer + import to its own file; add svc_external_svc_phone export format, + RT#4103 + +2008-11-06 22:04 ivan + + * httemplate/view/svc_acct.cgi: fix viewing of unlinked services. + wow, it has been a while + +2008-11-06 14:53 ivan + + * FS/FS/part_export/sqlradius.pm: should fix open session RADIUS + search, RT #4233 + +2008-11-06 14:20 ivan + + * FS/FS/part_export/sqlradius.pm: fix radius search, RT#4233 + +2008-11-05 20:22 ivan + + * FS/FS/svc_acct.pm: avoid harmless "Use of uninitialized value in + concatenation (.) or string at + /usr/local/share/perl/5.8.8/FS/svc_acct.pm line 1140" error + +2008-11-05 20:18 ivan + + * FS/FS/svc_acct.pm: . is used in some implementations of classic + crypt + +2008-11-03 07:28 jeff + + * FS/FS/cust_main.pm: REAL otherwise there are no taxes + +2008-11-03 07:26 jeff + + * FS/FS/cust_main.pm: yikes! not yet + +2008-11-03 07:14 jeff + + * FS/FS/cust_main.pm: otherwise there are no taxes + +2008-11-02 17:10 ivan + + * httemplate/view/svc_acct.cgi: time remaining is more useful to + display as hours + minutes than days, hours, minutes from + Time::Duration + +2008-11-02 12:27 ivan + + * httemplate/search/: cust_bill_pkg.cgi, report_tax.cgi: (and + REALLY fix the line-item links too, whew) fix overreporting of + tax invoiced when using & reporting with taxclasses, RT#4131 + +2008-11-02 12:03 ivan + + * httemplate/search/report_tax.cgi: (and fix the line-item links + too, whew) fix overreporting of tax invoiced when using & + reporting with taxclasses, RT#4131 + +2008-11-02 11:40 ivan + + * httemplate/search/report_tax.cgi: (and fix the total too) fix + overreporting of tax invoiced when using & reporting with + taxclasses, RT#4131 + +2008-11-02 11:26 ivan + + * httemplate/search/report_tax.cgi: fix overreporting of tax + invoiced when using & reporting with taxclasses, RT#4131 + +2008-11-01 15:12 ivan + + * init.d/freeside-init, FS/FS/Daemon.pm, FS/bin/freeside-cdrd: have + freeside-cdrd disable itself if there's no appropriate package + definition, RT#4184 + +2008-10-29 15:24 ivan + + * FS/FS/cust_main.pm: eek, fix agent_plandata from comping up with + spurious hits + +2008-10-29 13:23 ivan + + * FS/FS/part_event/Action.pm: remove debugging accidentally left in + +2008-10-29 13:21 ivan + + * FS/FS/part_event/Action.pm: huh. how did event editing ever + work? is this 5.10-specific? + +2008-10-29 01:03 ivan + + * FS/FS/cust_main.pm, init.d/freeside-init, + FS/FS/part_pkg/voip_cdr.pm, FS/bin/freeside-cdrd: prepaid cdr + pickup & bill daemon, RT#4184 + +2008-10-29 00:50 ivan + + * FS/FS/part_export/internal_diddb.pm: fix to internal_diddb + provisioning + +2008-10-27 18:23 ivan + + * FS/FS/svc_phone.pm: fix svc_phone non-numeric "phone numbers", + RT#4204 + +2008-10-24 17:37 ivan + + * FS/FS/: Conf.pm, svc_phone.pm: add a switch to allow letters in + phone numbers, RT#4195 + +2008-10-24 16:21 ivan + + * httemplate/view/svc_phone.cgi: correct links to non-US CDRs from + svc_phone view + +2008-10-24 15:53 ivan + + * fs_selfservice/FS-SelfService/SelfService/FreeRadiusVoip.pm: use + Reply-Message for the RADIUS error message, RT#4100 + +2008-10-24 15:23 ivan + + * FS/FS/ClientAPI/PrepaidPhone.pm: adding prepaid self-service + hooks, RT#4100 + +2008-10-24 14:31 ivan + + * FS/FS/: rate.pm, ClientAPI/PrepaidPhone.pm, part_pkg/voip_cdr.pm, + part_pkg/voip_sqlradacct.pm: adding prepaid self-service hooks, + RT#4100 + +2008-10-24 14:25 ivan + + * fs_selfservice/FS-SelfService/SelfService/: FreeRadiusVoip.pm: + rlm_perl hook for prepaid voip radius, RT#4100 + +2008-10-24 14:22 ivan + + * fs_selfservice/FS-SelfService/SelfService/FreeRadiusVoip.pm: + rlm_perl hook for prepaid voip radius, RT#4100 + +2008-10-24 12:58 ivan + + * fs_selfservice/FS-SelfService/SelfService/: FreeRadiusVoip.pm: + rlm_perl hook for prepaid voip radius, RT#4100 + +2008-10-24 12:54 ivan + + * fs_selfservice/FS-SelfService/: SelfService.pm, + SelfService/FreeRadiusVoip.pm: rlm_perl hook for prepaid voip + radius, RT#4100 + +2008-10-24 12:45 ivan + + * fs_selfservice/FS-SelfService/SelfService.pm: rlm_perl hook for + prepaid voip radius, RT#4100 + +2008-10-24 12:13 ivan + + * fs_selfservice/FS-SelfService/: SelfService.pm, + SelfService/FreeRadiusVoip.pm: rlm_perl hook for prepaid voip + radius, RT#4100 + +2008-10-23 19:54 ivan + + * FS/: FS/part_export/phone_sqlradius.pm, + FS/part_export/sqlradius.pm, bin/freeside-sqlradius-radacctd: + untested code to suck in CDRs in from VoIP RADIUS exports, + RT#4100 + +2008-10-23 19:08 ivan + + * FS/FS/cust_main.pm, httemplate/misc/xmlhttp-cust_main-search.cgi: + fixes to facilitate using agent_custid as custnum, RT#4190 + +2008-10-23 18:45 ivan + + * FS/: FS/svc_phone.pm, bin/freeside-sqlradius-reset: tiny nits for + phone RADIUS export: allow freeside-sqlradius-reset to reset a + phone_sqlradius export, but only if explicitly specified by + exportnum. also fix "Reference found where even-size list + expected" warning and junk winding up in radreply table". all + this phone_sqlradius stuff is RT#4100 + +2008-10-23 18:19 ivan + + * FS/FS/: Conf.pm, svc_phone.pm, part_export/phone_sqlradius.pm, + part_export/sqlradius.pm: add phone_sqlradius export + +2008-10-22 22:20 ivan + + * fs_selfservice/FS-SelfService/SelfService.pm: POD cleanup + +2008-10-22 11:50 ivan + + * httemplate/view/svc_phone.cgi: fix CDR links + +2008-10-21 21:39 ivan + + * FS/FS/part_export/sqlradius.pm, httemplate/search/sqlradius.cgi, + httemplate/search/sqlradius.html: fix error on open-ended RADIUS + search with Pg, add options for open session search and search on + start time, RT#4051 + +2008-10-21 08:50 jeff + + * fs_selfservice/java/: freeside_login_example.java, + freeside_signup_example.java, biz/freeside/SelfService.java: + biz.freeside.SelfService class and sample applications + +2008-10-18 18:57 ivan + + * httemplate/config/config.cgi: correctly allow re-editing of + config options with " in them + +2008-10-18 17:38 ivan + + * FS/FS/Schema.pm, FS/FS/agent.pm, httemplate/edit/agent.cgi, + httemplate/elements/search-cust_main.html, + httemplate/browse/agent.cgi: add a master custnum field to + agents, RT#2933 (roundabout) + +2008-10-17 18:22 jeff + + * FS/FS/cust_main.pm: sheesh + +2008-10-17 18:19 jeff + + * FS/FS/cust_main.pm: doh + +2008-10-17 18:08 jeff + + * FS/FS/cust_main.pm: cope with overlapping (but with distinct + endpoints) tax areas + +2008-10-17 13:01 jeff + + * conf/: invoice_latex, invoice_latexcoupon: address tweaks, + assumes a window at least 2.75in or 7cm wide + +2008-10-17 11:57 jeff + + * FS/FS/cust_bill.pm: correct erroneous line dupplication on + invoices + +2008-10-16 15:45 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add an option to use duration instead + of billsec to calculate billable time, RT#4147 + +2008-10-15 22:29 ivan + + * FS/FS/Conf_compat17.pm: sync Conf_compat17.pm + +2008-10-15 22:29 ivan + + * FS/FS/Conf.pm, httemplate/misc/payment.cgi, + httemplate/search/cust_pay_batch.cgi, + httemplate/view/cust_main/payment_history.html: add + batch-enable_payby and realtime_disable_payby for better control + over hybrid realtime/batch installs; deprecate never-used + paymentforcedtobatch, RT#4052 + +2008-10-15 22:04 ivan + + * httemplate/elements/menu.html: add batch-enable_payby and + realtime_disable_payby for better control over hybrid + realtime/batch installs; deprecate never-used + paymentforcedtobatch, RT#4052 + +2008-10-14 14:27 ivan + + * FS/FS/Tron.pm: not interested in payment gateway survey just now + +2008-10-13 17:50 ivan + + * FS/FS/cust_main.pm, httemplate/misc/cust_main-import.cgi: add an + import format for external services, including next bill date + (cust_pkg.bill), RT#4108 + +2008-10-13 14:58 ivan + + * FS/: bin/freeside-fetch, FS/Conf.pm: Change subject for + freeside-fetch emailed reports from "subject" to "Freeside + report", and add email_report-subject config to change it. + RT#4093 + +2008-10-12 16:56 jeff + + * conf/invoice_latex: better column widths and easier maintenance + +2008-10-12 14:22 jeff + + * conf/invoice_latex: better value for non-broken tetex + +2008-10-12 12:43 jeff + + * conf/longtable.sty.patch: check not just for fit, but move the + goalposts as well + +2008-10-11 17:58 ivan + + * httemplate/browse/cust_main_county.cgi: fix link + +2008-10-11 17:54 ivan + + * httemplate/: browse/cust_main_county.cgi, + edit/bulk-cust_main_county.html, + edit/process/bulk-cust_main_county.html: add a quick bulk tax add + tool (eating my own dogfood instead of running a one-off SQL + query), RT#4117 + +2008-10-10 17:32 ivan + + * FS/FS/: Conf.pm, cust_pkg.pm: enable suspension notices to an + administrator, RT#4083 + +2008-10-10 16:30 ivan + + * FS/FS/cust_pkg.pm: quick kludge to eliminate exact duplicates in + h_labels_short in an effort to reduce the number of "XXX service + listing twice on invoice" incidents, RT#3944. still should be + possible to fundamentally do better with the function in the + first place + +2008-10-10 14:30 jeff + + * conf/: invoice_latex, longtable.sty.patch: avoid overprinting + remittance coupons + +2008-10-10 12:25 ivan + + * FS/FS/cust_bill.pm: add options to auto-generate agent_custid and + display it as the customer number, RT#4099 + +2008-10-09 18:15 ivan + + * FS/FS/Conf.pm, FS/FS/cust_main.pm, + FS/FS/UI/Web/small_custview.pm, httemplate/index.html, + httemplate/view/cust_main/misc.html, FS/FS/UI/Web.pm, + httemplate/edit/cust_main.cgi, httemplate/search/cust_main.cgi: + add options to auto-generate agent_custid and display it as the + customer number, RT#4099 + +2008-10-09 13:06 ivan + + * FS/FS/part_export/sqlradius.pm: use Freeradius := attribute for + ALL attributes except Password. Crypt-Password, User-Password, + Password-With-Header should now use := instead of ==. RT#4051 + +2008-10-07 16:57 ivan + + * httemplate/misc/: cdr-import.html, process/cdr-import.html: put + each CDR web import into a batch + +2008-10-07 16:23 ivan + + * FS/FS/cdr/: genband.pm, nextone.pm: also set billsec for nextone + CDR format + +2008-10-06 17:10 ivan + + * FS/FS/Upgrade.pm: oops, brainfart + +2008-10-06 17:09 ivan + + * FS/FS/Upgrade.pm: when setting last_login/last_logout, ensure + only accounts actually attached to the export are updated + +2008-10-06 15:48 ivan + + * FS/FS/svc_acct.pm: make RADIUS password exports + _password_encoding-aware so we export Password-With-Header when + necessary + +2008-10-06 15:19 ivan + + * FS/FS/svc_acct.pm: make RADIUS password exports + _password_encoding-aware so we export Password-With-Header when + necessary + +2008-10-06 08:28 ivan + + * FS/FS/: cdr.pm, cdr/netcentrex.pm: add initial netcentrex CDR + format + +2008-10-05 14:36 ivan + + * httemplate/search/pay_batch.cgi: fix links to closed batches, + RT#4052 + +2008-10-05 03:17 ivan + + * httemplate/search/phone_avail.html: adding the start of available + phone# search. still needs a menu entry, search options page... + RT#3925 + +2008-10-04 23:07 ivan + + * httemplate/: edit/elements/ApplicationCommon.html, + view/cust_main/payment_history/credit.html, + view/cust_main/payment_history/payment.html: finish UI + improvements wrt refunds: now you have to post a check or cash + refund explicitly, no more implicit creation by 'applying' + credits. don't show useless application links. don't enable + apply button until you pick an invoice/refund. RT#3812 + +2008-10-04 15:35 ivan + + * FS/FS/: Misc.pm, cust_bill_ApplicationCommon.pm, + payinfo_transaction_Mixin.pm, Misc/prune.pm, rate_detail.pm, + usage_class.pm, part_event/Action.pm: POD cleanups + +2008-10-04 13:55 ivan + + * httemplate/edit/rate_region.cgi: fix inappropriate rounding when + editing rates for a whole region + +2008-10-04 13:43 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add disable_tollfree option + +2008-10-03 17:30 ivan + + * httemplate/edit/part_pkg.cgi: fix recurring box graying out on + package customize + +2008-10-03 12:41 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add debugging + +2008-09-30 14:05 jeff + + * httemplate/: search/report_newtax.cgi, search/cust_bill_pkg.cgi, + search/report_newtax.html, elements/menu.html: simple reporting + for new tax system + +2008-09-30 13:22 jeff + + * FS/FS/: Conf.pm, cust_main.pm: option for no postal fee on + one-time charges + +2008-09-30 13:17 jeff + + * fs_selfservice/FS-SelfService/cgi/: bill.html, selfservice.cgi: + turn on and off postal billing from self-service + +2008-09-28 20:41 ivan + + * httemplate/misc/delay_susp_pkg.html: use init_calendar.html + +2008-09-26 20:01 jeff + + * httemplate/edit/process/addr_block/manual_flag.cgi, + FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/addr_block.pm, + FS/FS/svc_broadband.pm, httemplate/browse/addr_block.cgi, + httemplate/edit/svc_broadband.cgi: per address block ip auto + assignment and auto router selection + +2008-09-25 20:54 jeff + + * FS/FS/part_event/Condition/dundate.pm, + httemplate/misc/delay_susp_pkg.html, FS/FS/AccessRight.pm, + FS/FS/Schema.pm, FS/FS/cust_main.pm, FS/FS/part_bill_event.pm, + httemplate/edit/part_bill_event.cgi, + httemplate/misc/process/delay_susp_pkg.html, + httemplate/view/cust_main/packages.html: push out event triggered + suspensions + +2008-09-25 16:44 jeff + + * FS/FS/cust_main.pm: lost bits of reason + +2008-09-24 19:27 jeff + + * FS/FS/part_export/prizm.pm: prizm export improvement for package + changes + +2008-09-18 16:17 jeff + + * FS/FS/Schema.pm: trade space for time + +2008-09-16 08:58 jeff + + * httemplate/search/report_tax.cgi: minor initialization issue + +2008-09-15 18:22 jeff + + * httemplate/: edit/part_pkg.cgi, edit/elements/edit.html, + elements/tr-select-taxoverride.html, + elements/tr-select-taxproduct.html: correct package editor when + taxproducts off + +2008-09-15 00:18 ivan + + * FS/FS/Schema.pm, FS/FS/Record.pm, FS/FS/phone_avail.pm, + FS/FS/part_export/internal_diddb.pm, + httemplate/elements/menu.html, + httemplate/misc/phone_avail-import.html, + httemplate/misc/process/phone_avail-import.html: add internal did + database & ability to query for availability, plus upload tool + +2008-09-14 17:40 ivan + + * FS/FS/part_export/globalpops_voip.pm: add dry_run option to + globalpops_voip export + +2008-09-14 13:24 ivan + + * FS/FS/cust_main_invoice.pm: silently strip out leading and + trailing spaces from invoicing email addresses instead of + throwing an error + +2008-09-14 13:20 ivan + + * httemplate/config/: config-process.cgi, config-view.cgi: don't + reload the whole page every time a config option is changed, + RT#3989 + +2008-09-14 12:13 ivan + + * httemplate/elements/header.html: default the menu to top in 1.9, + still a pref + +2008-09-12 15:53 ivan + + * FS/FS/part_pkg/voip_cdr.pm: just give up and try again tommorow, + "1011" came from us not the CDRs anyway, RT#3985 + +2008-09-12 15:48 ivan + + * FS/FS/part_pkg/voip_cdr.pm: not enough sleep to support multiple + internal_prefixen, RT#3985 + +2008-09-12 15:38 ivan + + * FS/FS/part_pkg/voip_cdr.pm: not enough sleep to support multiple + internal_prefixen, RT#3985 + +2008-09-12 15:18 ivan + + * FS/FS/part_pkg/voip_cdr.pm: grr, TRY to support multiple + internal_prefixen, RT#3985 + +2008-09-12 14:56 ivan + + * FS/FS/part_pkg/voip_cdr.pm: support multiple internal_prefixen, + RT#3985 + +2008-09-12 14:55 ivan + + * FS/FS/part_pkg/voip_cdr.pm: support multiple internal_prefixen + +2008-09-12 00:58 ivan + + * FS/FS/: Conf.pm, cust_pkg.pm: make the max # of indivudal + services printed on invoices configurable. RT#3904 + +2008-09-12 00:07 ivan + + * FS/FS/: part_pkg/flat.pm, part_pkg/voip_cdr.pm, cust_main.pm: + don't throw noisy warnings about missing new recur_temporality, + RT#3851 + +2008-09-11 19:28 jeff + + * FS/: FS/Schema.pm, FS/cust_bill.pm, FS/cust_bill_pkg.pm, + FS/cust_bill_pkg_display.pm, MANIFEST, FS/cust_main.pm, + t/cust_bill_pkg_display.t: re-repurpose cust_bill_pkg + +2008-09-11 19:01 ivan + + * FS/FS/cust_bill.pm, FS/FS/Conf.pm, + httemplate/misc/spool_invoices.cgi, + httemplate/search/cust_bill.html: add billco respooling, not + re-FTPing, RT#3971 + +2008-09-11 17:53 ivan + + * FS/FS/part_pkg/: flat.pm, voip_cdr.pm: add recur_temporality to + flat.pm, RT#3851 + +2008-09-11 17:41 ivan + + * FS/FS/cust_main.pm: correct a (fortunately harmless) typo + +2008-09-10 01:33 ivan + + * FS/FS/cust_bill.pm, FS/FS/Conf.pm, + httemplate/misc/ftp_invoices.cgi, + httemplate/search/cust_bill.html: add re-FTP reprint, + RT#create-me-tommorow-for-enet + +2008-09-10 00:55 ivan + + * FS/FS/Schema.pm: better (?) place to put display and taxation + data than overloading real line items + +2008-09-10 00:32 ivan + + * FS/FS/part_pkg.pm: well, allow things to work for now so work can + get done + +2008-09-10 00:30 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add upcoming/preceding option, + RT#3851 + +2008-09-10 00:24 ivan + + * FS/FS/cust_main.pm: add upcoming/preceding option, RT#3851 + +2008-09-09 15:35 ivan + + * FS/FS/ClientAPI/MyAccount.pm: allow implied primary services to + log into selfservice when selfservice_server-primary_only is on + +2008-09-09 14:29 ivan + + * FS/FS/ClientAPI/MyAccount.pm: this should allow implied primary + services to log into selfservice when + selfservice_server-primary_only is on + +2008-09-09 14:04 ivan + + * FS/FS/Upgrade.pm: show which _upgrade_data sub is being run + +2008-09-09 01:19 ivan + + * FS/FS/Schema.pm: wtf, cust_pkg_reason has no indices?! + _upgrade_data is hosing cpu badly + +2008-09-08 19:35 ivan + + * FS/FS/part_pkg/voip_cdr.pm: doh, forgot to display new options, + RT#3838 + +2008-09-08 19:24 ivan + + * FS/FS/: cdr.pm, cdr/taqua.pm, part_pkg/voip_cdr.pm: additional + QIS/Taqua-specific CDR handling details, RT#3838 + +2008-09-08 14:46 ivan + + * FS/FS/cust_main.pm: oops, debugging got left on by accident + +2008-09-08 14:23 ivan + + * httemplate/view/elements/svc_Common.html: also hide fixed+blank + fields on service view, RT#3829 + +2008-09-08 14:02 ivan + + * httemplate/edit/elements/svc_Common.html: completely hide + fixed+blank fields, RT#3829 + +2008-09-07 19:49 ivan + + * httemplate/edit/quick-charge.html: extraneous code cleanup + +2008-09-07 19:48 ivan + + * FS/FS/cust_bill_pkg.pm: removing unacceptable display fields from + cust_bill_pkg + +2008-09-07 19:47 ivan + + * FS/FS/: AccessRight.pm, cust_main.pm: add package invoice details + & comments, RT#3810 + +2008-09-07 19:42 ivan + + * FS/FS/Schema.pm, FS/FS/cust_pkg_detail.pm, FS/MANIFEST, + FS/t/cust_pkg_detail.t, httemplate/pref/pref-process.html, + httemplate/pref/pref.html, + httemplate/view/cust_main/packages.html, FS/FS.pm, + httemplate/edit/cust_pkg_detail.html, + httemplate/edit/process/cust_pkg_detail.html, FS/FS/cust_pkg.pm: + add package invoice details & comments, RT#3810 + +2008-09-06 13:54 ivan + + * FS/FS/UI/Web.pm: don't link to customer service view unless the + user has the ACL to view the resulting page + +2008-09-04 06:29 jeff + + * FS/FS/Upgrade.pm: three lost lines + +2008-09-03 20:10 ivan + + * httemplate/edit/invoice_logo.html: ask for an EPS for EPS upload, + not incorrectly a PNG + +2008-09-03 19:44 ivan + + * httemplate/edit/process/invoice_logo.html: fix invoice uplaoding + in light of database config where you absolutely need + ->set_binary for swtuf retreived with ->config_binary, RT#3936 + +2008-09-03 12:08 jeff + + * FS/FS/AccessRight.pm, FS/FS/access_right.pm, FS/FS/addr_block.pm, + FS/FS/router.pm, httemplate/browse/addr_block.cgi, + httemplate/browse/router.cgi, httemplate/browse/svc_acct_pop.cgi, + httemplate/edit/allocate.html, httemplate/edit/router.cgi, + httemplate/edit/svc_acct_pop.cgi, + httemplate/edit/process/router.cgi, + httemplate/edit/process/svc_acct_pop.cgi, + httemplate/edit/process/addr_block/add.cgi, + httemplate/edit/process/addr_block/allocate.cgi, + httemplate/edit/process/addr_block/deallocate.cgi, + httemplate/edit/process/addr_block/split.cgi, + httemplate/elements/menu.html: new access right names + +2008-09-03 11:59 jeff + + * FS/FS/: Upgrade.pm, cust_pkg_reason.pm: system only reason update + routine + +2008-09-02 18:52 ivan + + * httemplate/view/cust_main/payment_history.html: add back ability + to post a check/cash refund. be more explicit about it instead of + just being a checkbox when posting a credit. RT#3812 + +2008-09-02 18:46 ivan + + * FS/FS/payby.pm, httemplate/edit/cust_pay.cgi, + httemplate/edit/cust_refund.cgi, + httemplate/edit/process/cust_refund.cgi, + httemplate/elements/init_calendar.html, + httemplate/view/cust_refund.html, + httemplate/view/cust_main/payment_history/refund.html, + FS/FS/AccessRight.pm: add back ability to post a check/cash + refund. be more explicit about it instead of just being a + checkbox when posting a credit. RT#3812 + +2008-09-02 08:37 jeff + + * FS/FS/: cust_bill.pm, cust_bill_pkg.pm, ClientAPI/MyAccount.pm: + call details in self-service + +2008-08-30 14:34 jeff + + * FS/FS/Conf.pm, FS/FS/cust_bill.pm, FS/FS/cust_bill_pkg.pm, + FS/FS/cust_main.pm, FS/FS/Report/Table/Monthly.pm, + FS/FS/part_pkg/voip_cdr.pm, httemplate/search/cust_bill_pkg.cgi, + httemplate/search/report_prepaid_income.cgi, + httemplate/search/report_tax.cgi: remove duplicate cust_bill_pkg + creation RT#3919 + +2008-08-29 19:10 jeff + + * FS/FS/cust_bill_pkg.pm, FS/FS/cust_main.pm, FS/FS/tax_rate.pm, + httemplate/edit/process/part_pkg.cgi: bug squashing for multiple + usage classes + +2008-08-29 16:13 ivan + + * FS/FS/part_export/acct_freeside.pm: adding fs-to-fs provisioning + of simple accounts for cheepnet, RT#3805 + +2008-08-29 13:10 ivan + + * httemplate/elements/tr-pkg_svc.html: increase maxlength and size + of quantity fields on package edit, for RT#3805 + +2008-08-28 18:09 ivan + + * FS/FS/Schema.pm, FS/FS/cdr.pm, bin/cdr.sftp_and_import, + httemplate/elements/select-cdrbatch.html, + httemplate/elements/tr-select-cdrbatch.html, + httemplate/search/cdr.html, httemplate/search/report_cdr.html: + add CDR batch TFTP feature, RT#3113 + +2008-08-28 17:45 jeff + + * FS/FS/part_pkg.pm: noise reduction + +2008-08-28 17:23 ivan + + * httemplate/elements/: tr-select-taxclass.html, + select-taxclass.html: correct nits in tax class selection + +2008-08-28 15:00 jeff + + * FS/FS/tax_rate.pm: updates can be completely empty + +2008-08-28 14:32 jeff + + * FS/FS/cust_main.pm, FS/FS/part_pkg.pm, + httemplate/browse/part_pkg_taxproduct.cgi, + httemplate/edit/part_pkg_taxoverride.html, + httemplate/edit/quick-charge.html, + httemplate/edit/process/quick-charge.cgi, + httemplate/elements/select-taxoverride.html, + httemplate/elements/select-taxproduct.html, + httemplate/view/cust_main/packages.html: taxproduct selection for + one time charges + +2008-08-28 12:09 ivan + + * FS/FS/: Tron.pm, Yori.pm: payment gateway survey + +2008-08-28 00:38 jeff + + * httemplate/elements/select-taxoverride.html, + httemplate/elements/select-taxproduct.html, + httemplate/elements/tr-select-taxoverride.html, + httemplate/elements/tr-select-taxproduct.html, FS/FS/Schema.pm, + FS/FS/cust_bill_pkg.pm, FS/FS/cust_main.pm, FS/FS/part_pkg.pm, + FS/FS/part_pkg/voip_cdr.pm, + httemplate/browse/part_pkg_taxproduct.cgi, + httemplate/edit/part_pkg.cgi, + httemplate/edit/part_pkg_taxoverride.html, + httemplate/edit/process/part_pkg.cgi: multiple usage classes + checkpoint + +2008-08-26 17:15 ivan + + * FS/FS/cust_main.pm: don't override countrydefault or whatever + with a blank value in bulk customer import + +2008-08-26 17:05 ivan + + * httemplate/elements/mcp_lint.html: add unchecked vs. ok + distinction to lint + +2008-08-26 17:00 ivan + + * httemplate/elements/mcp_lint.html: add unchecked vs. ok + distinction to lint + +2008-08-26 16:53 ivan + + * FS/FS/Tron.pm, httemplate/elements/mcp_lint.html: add unchecked + vs. ok distinction to lint + +2008-08-26 07:00 rsiddall + + * rpm/freeside.spec: More changes to the self-service RPMs, mostly + fixing up paths so the RPM-installed self-service files are not + under /usr/local on the remote machine. Also fixed an + initialization problem where the system configuration files for + Freeside were assumed to be under /etc/default, not + /etc/sysconfig + +2008-08-25 14:23 ivan + + * httemplate/edit/elements/edit.html: fix package editor showing + "all" for pkg class selection + +2008-08-25 13:33 ivan + + * FS/FS/part_event/Condition/cust_bill_has_service.pm: fix + comparison from svcnum to svcpart + +2008-08-24 22:53 jeff + + * FS/FS/Schema.pm, FS/FS/cust_bill_pkg.pm, + FS/FS/Report/Table/Monthly.pm, + httemplate/search/cust_bill_pkg.cgi, + httemplate/search/report_prepaid_income.cgi, + httemplate/search/report_tax.cgi: correct fallout from duplicate + line items + +2008-08-24 22:18 jeff + + * httemplate/search/cust_tax_exempt_pkg.cgi: correct fallout from + agent virtualizing packages + +2008-08-24 15:35 ivan + + * httemplate/elements/checkboxes-table-name.html: add controls to + select/unselect/toggle all checkboxes + +2008-08-24 14:52 ivan + + * bin/customer-faker: add -k option for pkgpart + +2008-08-24 14:49 ivan + + * bin/customer-faker: add -a option for agentnum + +2008-08-23 20:41 rsiddall + + * rpm/freeside.spec: Create discrete RPMs for different parts of + the self-service interface. Put the default configuration folder + in the main freeside RPM. + +2008-08-23 14:59 jeff + + * FS/FS/Mason.pm, FS/FS/Schema.pm, FS/FS/usage_class.pm, + FS/FS/Setup.pm, FS/FS/Upgrade.pm, FS/FS/rate_detail.pm, + FS/t/usage_class.t, httemplate/browse/usage_class.html, FS/FS.pm, + FS/MANIFEST, httemplate/browse/rate_detail.html, + httemplate/edit/rate_detail.html, + httemplate/edit/rate_region.cgi, + httemplate/edit/usage_class.html, + httemplate/edit/elements/edit.html, + httemplate/edit/process/rate_region.cgi, + httemplate/edit/process/usage_class.html, + httemplate/elements/menu.html: add usage classes to rate details + +2008-08-22 20:29 jeff + + * FS/FS/: Record.pm, cust_main.pm, part_pkg_taxrate.pm, + tax_rate.pm: tax data update bug fixes and error message + improvements + +2008-08-21 20:01 ivan + + * FS/FS/Mason.pm, FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/Tron.pm, + FS/FS/cust_svc.pm, FS/FS/cust_svc_option.pm, bin/tron-scan, + FS/MANIFEST, FS/t/cust_svc_option.t, + httemplate/elements/dashboard-toplist.html, + httemplate/elements/mcp_lint.html: the master control program has + chosen YOU to serve your system on the game grid + +2008-08-21 16:21 ivan + + * FS/: FS/Yori.pm, bin/freeside-yori, MANIFEST: add the client-side + reporting for MCP mode + +2008-08-21 11:21 jeff + + * bin/import-optigold.pl: use options with proper names + +2008-08-19 11:42 ivan + + * FS/FS/svc_acct.pm: beter error messages for duplicate accounts + +2008-08-19 04:35 ivan + + * FS/FS/cdr.pm: fix duration on simple/simple2 CDR formats + +2008-08-19 03:09 ivan + + * httemplate/edit/process/rate_region.cgi: also don't neglext nxx + here + +2008-08-19 03:06 ivan + + * FS/FS/rate_region.pm, httemplate/browse/rate_region.html, + httemplate/edit/rate_region.cgi: more consistent prefix display, + and don't forget nxx' + +2008-08-15 12:42 ivan + + * Makefile: install default conf with make create-config too, so it + doesn't go missing + +2008-08-15 12:26 ivan + + * FS/bin/freeside-setup: allow a full pathname to be specified to + freeside-setup for initial configdir + +2008-08-14 18:09 jeff + + * FS/FS/tax_class.pm: correct field ordering - invonsequential + +2008-08-14 17:41 ivan + + * httemplate/elements/form-file_upload.html: can have a message + then a URL too + +2008-08-14 04:53 ivan + + * FS/FS/Schema.pm, FS/FS/UID.pm, FS/FS/cust_main.pm, + httemplate/elements/progress-init.html, + httemplate/misc/cust_main-import.cgi, + httemplate/misc/process/cust_main-import.cgi, + httemplate/elements/progress-popup.html, + httemplate/search/cust_main.html, + httemplate/elements/form-file_upload.html, + httemplate/misc/file-upload.html, + httemplate/elements/file-upload.html: customer import: add + progress bar & redirect to a search of the imported customers, + #3475 + +2008-08-14 04:44 ivan + + * FS/FS/tax_rate.pm, httemplate/misc/tax-import.cgi: customer + import: add progress bar & redirect to a search of the imported + customers, #3475 + +2008-08-13 18:58 ivan + + * FS/FS/Conf.pm, FS/FS/Record.pm, FS/FS/cust_main.pm, + httemplate/elements/menu.html, + httemplate/misc/cust_main-import.cgi, + httemplate/misc/process/cust_main-import.cgi: import customer + from Excel file too + +2008-08-13 18:52 ivan + + * FS/FS/svc_Common.pm: tyop + +2008-08-13 18:38 ivan + + * httemplate/view/svc_forward.cgi: tyop + +2008-08-08 13:29 jeff + + * bin/import-optigold.pl: better opti table relationship following + +2008-08-08 11:13 jeff + + * FS/FS/Schema.pm, FS/FS/cust_bill.pm, FS/FS/cust_bill_pkg.pm, + FS/FS/cust_main.pm, FS/FS/part_pkg/voip_cdr.pm, + conf/invoice_latex: cdrs can be in separate invoice section, + after total, summarized inline, with hints for page breaks + +2008-08-07 15:30 ivan + + * Makefile: don't generate a new key on install-selfservice if + there's already an RSA one either + +2008-08-05 23:39 jeff + + * FS/FS/part_pkg/voip_cdr.pm: prevent adding 0 value line items + +2008-08-05 21:05 jeff + + * FS/FS/cust_main.pm: fix bug(s) introduced with billing loop + refactor + +2008-08-02 19:15 ivan + + * FS/FS/Schema.pm, FS/FS/svc_phone.pm, + httemplate/edit/svc_phone.cgi, httemplate/view/svc_phone.cgi: add + a name field to svc_phone + +2008-08-02 17:54 ivan + + * FS/FS/cdr/simple2.pm: doh, fix regex + +2008-08-02 17:26 ivan + + * FS/FS/: Record.pm: attempt to eliminate 'Can't call method + "exists" on an undefined value at + /usr/local/share/perl/5.8.8/FS/Record.pm line 812.' error on + upgrade + +2008-08-02 17:20 ivan + + * FS/FS/Record.pm: attempt to eliminate 'Can't call method "exists" + on an undefined value at /usr/local/share/perl/5.8.8/FS/Record.pm + line 812.' error on upgrade + +2008-08-02 16:51 ivan + + * FS/FS/: cdr.pm, cdr/asterisk.pm, cdr/genband.pm, + cdr/genband_meetme.pm, cdr/nextone.pm, cdr/openser.pm, + cdr/simple.pm, cdr/taqua.pm, cdr/unitel.pm, cdr/simple2.pm: fix + 'Can't call method "parse" on an undefined value' error from CDR + format refactor + +2008-08-01 21:20 jeff + + * FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/cust_bill.pm, + FS/FS/cust_bill_pkg.pm, FS/FS/cust_main.pm, + FS/FS/part_pkg/voip_cdr.pm, conf/invoice_html, + conf/invoice_latex, httemplate/edit/cust_main.cgi, + httemplate/edit/cust_main/billing.html, + httemplate/view/cust_main/billing.html: bundled package + presentation improvements + +2008-08-01 21:09 jeff + + * FS/FS/: Schema.pm, Upgrade.pm, cust_bill.pm, cust_bill_pkg.pm, + cust_bill_pkg_detail.pm, cust_main.pm, part_pkg.pm, + part_pkg/voip_cdr.pm: improve CDR usage presentation + +2008-08-01 14:41 ivan + + * FS/FS/cust_main.pm: fix receivables report: credits/etc. should + be limited by date like before, closes: Bug#3801 + +2008-08-01 13:21 ivan + + * httemplate/edit/pkg_class.html: categories deserve labels too + +2008-07-31 16:32 ivan + + * httemplate/search/report_receivables.cgi: this should fix columns + not showing up in receivables report... not surea bout #3801 + (credits/etc show up in all time periods) + +2008-07-31 13:17 ivan + + * httemplate/search/report_receivables.cgi, FS/FS/cust_main.pm: fix + receivables report: credits/etc. should be limited by date like + before, closes: Bug#3801 + +2008-07-30 19:35 ivan + + * httemplate/misc/delete-customer.cgi: fix error on customer + deletion + +2008-07-30 15:10 ivan + + * FS/FS/cdr/: nextone.pm, nt.pm: rename nt to nextone + +2008-07-29 13:00 jeff + + * FS/FS/cust_bill.pm: correct amount for new charges total on + sectioned invoices + +2008-07-29 10:29 rsiddall + + * rpm/freeside.spec: Self-Service files were reorganized; changed + the way we copy them into the buildroot. + +2008-07-24 09:40 jeff + + * FS/FS/cust_bill.pm: ensure invoice line items are delivered in + line number order + +2008-07-23 07:41 jeff + + * httemplate/edit/tax_rate.html: add disabled column to new tax + rates, false laziness elimination, and bug fixes - closes #3566 + +2008-07-23 07:36 jeff + + * FS/FS/Schema.pm, FS/FS/tax_rate.pm, + httemplate/browse/tax_rate.cgi, + httemplate/misc/enable_or_disable_tax.html, + httemplate/misc/process/enable_or_disable_tax.html: add disabled + column to new tax rates, false laziness elimination, and bug + fixes - closes #3566 + +2008-07-22 01:33 ivan + + * FS/FS/part_export/phone_shellcommands.pm: freepbx modification + command + +2008-07-21 21:59 ivan + + * httemplate/view/svc_phone.cgi: add "incoming CDRs" link to phone# + view also + +2008-07-21 15:34 ivan + + * FS/FS/ClientAPI/Signup.pm, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/cgi/signup.cgi, + fs_selfservice/FS-SelfService/cgi/signup.html, + fs_selfservice/FS-SelfService/cgi/success.html: svc_phone signup + +2008-07-21 14:23 ivan + + * Makefile: oops, don't inadvertantly switch default db type + +2008-07-21 12:09 ivan + + * FS/FS/Conf.pm, httemplate/elements/select-did.html, + FS/FS/ClientAPI/MasonComponent.pm, FS/FS/ClientAPI/Signup.pm, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/cgi/signup.html, + fs_selfservice/FS-SelfService/cgi/misc/areacodes.cgi, + fs_selfservice/FS-SelfService/cgi/misc/exchanges.cgi, + fs_selfservice/FS-SelfService/cgi/images/cross.png, + fs_selfservice/FS-SelfService/cgi/images/wait-orange.gif, + fs_selfservice/FS-SelfService/cgi/misc/phonenums.cgi: signup + w/globalpops DID selection via mason components pass-through + +2008-07-21 11:58 ivan + + * FS/MANIFEST, htetc/handler.pl, FS/FS/CGI.pm, FS/FS/Mason.pm, + FS/FS/Mason/Request.pm, Makefile: add framework for running Mason + components standalone + +2008-07-21 03:42 ivan + + * FS/FS/svc_phone.pm: generate a SIP password if it is blank + +2008-07-18 15:31 ivan + + * httemplate/search/report_rt_transaction.html: missing closing + FORM tag + +2008-07-18 15:30 ivan + + * httemplate/elements/popup_link.html: add target param, i thought + this was needed for something... + +2008-07-18 15:29 ivan + + * bin/bind.import: add -e option to bind.import (now to actually + implement it) + +2008-07-18 15:28 ivan + + * FS/FS/rate_region.pm: show NXX is US if applicable + +2008-07-18 15:28 ivan + + * FS/FS/: h_cust_svc.pm, part_export.pm, part_pkg.pm, svc_acct.pm, + UI/Web.pm: some random cleanups + +2008-07-18 15:27 ivan + + * FS/FS/Record.pm: add no_check_foreign kludge for gigantic rate + imports + +2008-07-18 15:26 ivan + + * FS/MANIFEST: add part_pkg_link to MANIFEST + +2008-07-17 16:55 ivan + + * FS/FS/: cdr.pm, cdr/asterisk.pm, cdr/genband.pm, + cdr/genband_meetme.pm, cdr/nt.pm, cdr/openser.pm, cdr/simple.pm, + cdr/taqua.pm, cdr/unitel.pm: CDR updates; modularize CDR import + formats; add formats for OpenSER, Genband/Tekelec, and "NT" + +2008-07-16 16:55 ivan + + * httemplate/search/svc_acct.cgi: fix account search by time + remaining to deal with situations w/o a recurring amount + +2008-07-15 16:25 ivan + + * FS/FS/Upgrade.pm: where in the world is $DBI::errstr + +2008-07-15 16:18 ivan + + * FS/FS/Upgrade.pm: parens help alot + +2008-07-15 16:17 ivan + + * FS/FS/Upgrade.pm: report errors connecting to sqlradius dbs on + upgrade + +2008-07-15 13:56 ivan + + * FS/FS/cust_main.pm: prevent inactive customers from showing up in + reports of cancelled customers + +2008-07-14 18:19 ivan + + * FS/FS/part_export/phone_shellcommands.pm: add warning about + concurrency in FreePBX + +2008-07-14 16:59 ivan + + * httemplate/view/cust_main/notes.html: fuck embedded iframes and + their stupid display problems with scrolling. also make the + gridding more consistent + +2008-07-14 16:08 ivan + + * httemplate/: edit/process/cust_main_note.cgi, view/cust_main.cgi, + view/cust_main/notes.html: fuck embedded iframes and their stupid + display problems with scrolling. also make the gridding more + consistent + +2008-07-10 11:48 ivan + + * httemplate/view/cust_main/packages.html: fix variable scoping + issues preventing customer view page from coing up + +2008-07-09 20:16 jeff + + * FS/FS/cust_bill.pm: restore line item date ranges + +2008-07-09 13:37 ivan + + * FS/FS/part_pkg.pm: should avoid spurious uninitialized value + warnings on upgrade + +2008-07-09 13:33 ivan + + * FS/FS/svc_Common.pm: perl vs SQL brainfart + +2008-07-09 12:45 ivan + + * httemplate/docs/license.html: fix famfamfam link + +2008-07-09 12:35 ivan + + * FS/FS/svc_Common.pm: service searching should be case-insensitive + now + +2008-07-08 20:40 ivan + + * httemplate/search/: cust_tax_exempt.cgi: helpful to see when + exemptions were inserted? + +2008-07-08 20:27 ivan + + * httemplate/search/cust_tax_exempt.cgi: need the exemptnum... + +2008-07-08 20:18 ivan + + * httemplate/search/: cust_tax_exempt.cgi, cust_tax_exempt.html: + search legacy tax exemptions by customer status + +2008-07-08 19:30 ivan + + * httemplate/edit/process/part_pkg.cgi: don't require an agent type + to be specified when editing a disabled package + +2008-07-07 19:19 ivan + + * httemplate/search/cust_bill_pkg.cgi: fix line-item reports on + taxclass-less regions + +2008-07-07 19:01 ivan + + * FS/FS/cust_main_county.pm, httemplate/search/cust_bill_pkg.cgi, + httemplate/search/report_tax.cgi: fix line-item reports on + taxclass-less regions + +2008-07-07 17:35 ivan + + * httemplate/search/cust_bill_pkg.cgi: order by number for line + items with the same datestamp + +2008-07-07 17:20 ivan + + * httemplate/search/cust_bill_pkg.cgi: order line item reports by + date + +2008-07-07 16:47 ivan + + * httemplate/search/report_tax.cgi: should be a proper fix for edge + cases where you have taxclass and empty-taxclass rates for a + region, whew + +2008-07-07 14:38 ivan + + * FS/FS/Record.pm: SQL_FLOAT is probably unnecessary and causes + probelms on old (v1.x?) DBD::Pg + +2008-07-07 14:18 ivan + + * FS/FS/Record.pm: eek, hopefully fix problems caused by adding + debugging of bind_param statements + +2008-07-07 14:07 ivan + + * FS/FS/Record.pm: add debugging of bind_param statements + +2008-07-07 12:50 ivan + + * FS/FS/Record.pm: add debugging of bind_param statements + +2008-07-03 16:23 ivan + + * httemplate/view/cust_main/packages.html: fix bad sub names in + forward-port + +2008-07-02 21:19 ivan + + * FS/FS/Record.pm: should FINALLY get binding correctly in light of + regression caused by get_real_fields refactor + +2008-07-02 21:12 ivan + + * FS/FS/Record.pm: this should non-"=" searches on fields that + require SQL type binding... + +2008-07-02 21:00 ivan + + * FS/FS/cust_pkg.pm: correct hash vs hashref brainfart on + "forward-port", i guess + +2008-07-02 20:57 ivan + + * FS/FS/Record.pm: real should be bound to SQL_FLOAT Like float4... + 1.7? not touching it unless it breaks :) + +2008-07-01 19:55 ivan + + * FS/FS/ClientAPI/MyAccount.pm: fix errors paying with an on-file + card through self-service + +2008-07-01 00:02 jeff + + * FS/FS/cust_pkg.pm: you shouldn't keep 'em separated + +2008-06-30 22:01 jeff + + * httemplate/misc/unadjourn_pkg.cgi, + httemplate/misc/unexpire_pkg.cgi, FS/FS/Schema.pm, + FS/FS/cust_pkg.pm, FS/FS/cust_pkg_reason.pm, + FS/FS/part_export/shellcommands.pm, + FS/FS/part_export/sqlradius.pm, + httemplate/edit/REAL_cust_pkg.cgi, + httemplate/misc/process/cancel_pkg.html, + httemplate/search/cust_pkg.cgi, + httemplate/view/cust_main/packages.html: correct internal reason + searching, prevent interleaved suspend/cancel/expire/adjourn, + backporting and refactoring + +2008-06-30 17:11 ivan + + * FS/FS/svc_phone.pm: that should fix new sip_password field, whew + +2008-06-30 17:07 ivan + + * FS/FS/svc_phone.pm: that should fix the new sip_password field, i + hope + +2008-06-30 17:00 ivan + + * httemplate/view/svc_phone.cgi: add sip pw display + +2008-06-30 16:56 ivan + + * FS/FS/Schema.pm, FS/FS/svc_phone.pm, + FS/FS/part_export/phone_shellcommands.pm, + httemplate/edit/svc_phone.cgi: add sip pw field + +2008-06-30 01:01 ivan + + * fs_selfservice/FS-SelfService/cgi/: signup.cgi, signup.html: + checkpoint signup work + +2008-06-30 01:00 ivan + + * FS/FS/part_export/phone_shellcommands.pm: reload after adding + extensions + +2008-06-29 13:53 ivan + + * FS/FS/svc_phone.pm, FS/FS/part_export/globalpops_voip.pm, + httemplate/elements/select-phonenum.html, + httemplate/elements/tr-select-did.html: globalPOPs provisioning + +2008-06-28 21:33 jeff + + * httemplate/view/cust_main/packages.html: spurious 'suspended' + +2008-06-28 17:41 ivan + + * FS/: MANIFEST, FS.pm, t/phone_avail.t, FS/Schema.pm, + FS/phone_avail.pm, FS/part_export/globalpops_voip.pm: + state->areacode caching, + +2008-06-28 16:03 ivan + + * httemplate/images/wait-orange.gif, FS/FS/part_svc.pm, + httemplate/edit/elements/svc_Common.html, + httemplate/elements/input-text.html, + httemplate/elements/select-areacode.html, + httemplate/elements/select-did.html, + httemplate/elements/select-exchange.html, + httemplate/elements/select-phonenum.html, + httemplate/elements/select-state.html, + httemplate/elements/tr-input-text.html, + httemplate/elements/tr-select-did.html, + httemplate/misc/areacodes.cgi, httemplate/misc/exchanges.cgi, + httemplate/misc/phonenums.cgi, FS/FS/Record.pm, + FS/FS/part_export/globalpops_voip.pm, + httemplate/edit/svc_phone.cgi, + httemplate/edit/cust_main/select-state.html: get DIDs from + globalpops + +2008-06-28 12:25 jeff + + * httemplate/elements/tr-checkboxes-table.html, + httemplate/elements/checkboxes-table.html, + httemplate/elements/menu.html, + httemplate/elements/select-agent.html, + httemplate/elements/select-table.html, FS/FS/AccessRight.pm, + FS/FS/addr_block.pm, FS/FS/router.pm, FS/FS/svc_broadband.pm, + httemplate/browse/addr_block.cgi, httemplate/browse/router.cgi, + httemplate/browse/svc_acct_pop.cgi, + httemplate/edit/allocate.html, httemplate/edit/router.cgi, + httemplate/edit/svc_acct_pop.cgi, + httemplate/edit/svc_broadband.cgi, + httemplate/edit/elements/edit.html, + httemplate/edit/elements/svc_Common.html, + httemplate/edit/process/router.cgi, + httemplate/edit/process/svc_acct_pop.cgi, + httemplate/edit/process/svc_broadband.cgi, + httemplate/edit/process/addr_block/add.cgi, + httemplate/edit/process/addr_block/allocate.cgi, + httemplate/edit/process/addr_block/deallocate.cgi, + httemplate/edit/process/addr_block/split.cgi, + httemplate/edit/process/elements/process.html: agent virtualize + address blocks and routers + +2008-06-27 01:53 ivan + + * FS/FS/Conf.pm, FS/FS/ClientAPI/Signup.pm, fs_selfservice/DEPLOY, + fs_selfservice/FS-SelfService/SelfService.pm, + fs_selfservice/FS-SelfService/cgi/signup.html: adding + signup_server-service config + +2008-06-27 00:18 ivan + + * FS/FS/part_export/globalpops_voip.pm: globalpops_voip export + compilation fixes + +2008-06-26 17:27 ivan + + * FS/FS/part_export/globalpops_voip.pm: commiting globalpops export + start. stupid power failure. + +2008-06-26 14:55 ivan + + * FS/FS/part_export/phone_shellcommands.pm: adding + phone_shellcommands with preliminary FreePBX integration commands + +2008-06-25 13:14 ivan + + * httemplate/search/report_receivables.cgi: optimize total query in + receivables report. very significant speedup for large DBs + +2008-06-25 13:11 ivan + + * FS/FS/: cust_main.pm, cust_bill.pm: POD updates + +2008-06-25 11:14 ivan + + * FS/FS/Upgrade.pm: don't show error messages about FreesideStatus + index already existing either + +2008-06-24 17:29 ivan + + * htetc/handler.pl, FS/FS/Record.pm: finish adding + str2time_sql_closing + +2008-06-24 11:50 ivan + + * conf/invoice_html: i think we need a $ there??? + +2008-06-24 09:39 jeff + + * FS/FS/: Conf.pm, Conf_compat17.pm, cust_main.pm: postal invoice + fees + +2008-06-23 19:09 ivan + + * FS/FS/part_export/sqlradius.pm: prevent decrementing + time/bandwidth for old RADIUS records + +2008-06-23 15:59 ivan + + * bin/cdr.import: hahahd doh, we're in perl + +2008-06-23 15:11 ivan + + * bin/cdr.import: add quick command line too for CDR imports + +2008-06-23 09:46 jeff + + * conf/invoice_html: this is what it was for + +2008-06-23 08:36 jeff + + * FS/FS/cust_bill.pm, conf/invoice_html, conf/invoice_latex: + invoice service address modifications + +2008-06-22 19:50 ivan + + * conf/invoice_html: wtf was this for in the first place then + +2008-06-22 19:48 ivan + + * conf/invoice_html: this seems to match the latex templates more + accurately, rather than push the sub-totals out into their own + column + +2008-06-22 19:35 ivan + + * conf/invoice_html: fix leaking colspan in totals on sectioned + invoices + +2008-06-22 17:41 ivan + + * FS/FS/cust_tax_exempt.pm: adding report on legacy tax exemptions + to assist in enet migraiton + +2008-06-22 17:37 ivan + + * httemplate/search/cust_tax_exempt.cgi: legacy tax exemption + report fix, no _date + +2008-06-22 17:34 ivan + + * httemplate/search/cust_tax_exempt.cgi: adding report on legacy + tax exemptions to assist in enet migraiton + +2008-06-19 22:47 jeff + + * FS/FS/cust_bill.pm: extra values for invoices + +2008-06-19 20:36 ivan + + * FS/FS/: cdr.pm, part_pkg/voip_cdr.pm: VoxLineSystems are lying + scum who charged back their customization work and then used the + software anyway + +2008-06-18 20:18 jeff + + * FS/FS/pkg_category.pm, FS/FS/Schema.pm, FS/FS/cust_bill.pm, + FS/FS/part_pkg.pm, FS/FS/pkg_class.pm, FS/t/pkg_category.t, + FS/FS.pm, httemplate/browse/pkg_category.html, + httemplate/browse/pkg_class.html, + httemplate/edit/pkg_category.html, + httemplate/edit/pkg_class.html, + httemplate/edit/process/pkg_category.html, FS/MANIFEST, + htetc/handler.pl, httemplate/edit/elements/edit.html, + httemplate/elements/menu.html: package categories (meta package + classes) and grouping invoices by them + +2008-06-18 14:18 ivan + + * FS/FS/Misc.pm: fix regression caused by use of IPC::Run to run + pslatex: send STDOUT and STDERR from pslatex to /dev/null, we + don't want them + +2008-06-18 12:24 ivan + + * httemplate/edit/part_pkg.cgi: s helps alot + +2008-06-18 12:09 ivan + + * httemplate/edit/part_pkg.cgi: fix setup/recur fees on cloning + (customizing) package definitions w/new editor + +2008-06-18 11:50 jeff + + * httemplate/: browse/tax_rate.cgi, + misc/enable_or_disable_tax.html, + misc/process/enable_or_disable_tax.html: allow enabling and + disabling if tax_rate rows in groups (RT 3566) + +2008-06-17 22:22 ivan + + * FS/FS/cust_main.pm: %statuscolor is either a global or a my var, + make up your mind + +2008-06-17 17:49 ivan + + * FS/FS/part_virtual_field.pm: this module, also, has no need to + import qsearch/qsearchs, and is causing dependency loop problems + (Record->part_virtual_field->Record) + +2008-06-17 17:46 ivan + + * FS/FS/Record.pm: hopefully finally fix the dependency loops bs... + as simple as Record->Conf->Record here + +2008-06-17 17:42 ivan + + * FS/FS/Msgcat.pm: REALLY, don't use FS::Conf from Msgcat until + runtime... should hopefully FINALLY eliminate the + Record->Msgcat->Conf->Record loop + +2008-06-17 17:36 ivan + + * FS/FS/msgcat.pm: msgcat.pm doesn't actually need + qsearch/qsearchs... hopefully this is the last of the weird + dependency loops (this one is Record->Msgcat->msgcat->Record) + +2008-06-17 17:27 ivan + + * FS/FS/Msgcat.pm: fix dependency loop problem with database + config, hopefully? (Record->Msgcat->Conf->Record) + +2008-06-17 17:10 ivan + + * FS/FS/conf.pm: conf.pm doesn't actually need qsearch/qsearchs - + hopefully this will solve the weird circular dependency issue + (Record->Msgcat->Conf->conf->Record) + +2008-06-17 17:05 ivan + + * httemplate/misc/xmlhttp-cust_main-address_standardize.html: turn + off debugging for address standardization + +2008-06-17 16:57 ivan + + * httemplate/edit/part_pkg.cgi: don't lose the pricing on package + cloning w/new package editor + +2008-06-17 12:29 jeff + + * conf/invoice_latex: fixup damage from quantity addition + +2008-06-16 20:35 ivan + + * FS/FS/AccessRight.pm, httemplate/edit/invoice_template.html, + FS/FS/ConfDefaults.pm, FS/FS/Misc.pm, FS/FS/cust_main.pm, + htetc/handler.pl, httemplate/elements/htmlarea.html, + httemplate/misc/email-customers.html, + httemplate/misc/process/email-customers.html, + httemplate/search/cust_main.html: finish adding a feature to + easily list all email addresses for an agent & send them email + +2008-06-16 20:13 jeff + + * conf/invoice_latex: not forgetting to add fax and old customer id + +2008-06-16 18:43 ivan + + * httemplate/edit/process/cust_main.cgi: have agent_custid editing + now + +2008-06-16 06:36 jeff + + * bin/import-optigold.pl: catch one more customer + +2008-06-15 23:53 ivan + + * FS/FS/Conf.pm, httemplate/edit/cust_main.cgi: add (with config) + ability to edit agent_custid + +2008-06-15 18:32 jeff + + * bin/import-optigold.pl: ugh; cast about for svc/pkg linkages + +2008-06-12 16:15 ivan + + * httemplate/edit/REAL_cust_pkg.cgi: fix visual regression not + displaying package and comment on date editing + +2008-06-12 14:53 ivan + + * httemplate/: edit/process/elements/process.html, + view/cust_main/packages.html, edit/part_pkg.cgi, + edit/elements/edit.html, edit/process/part_pkg.cgi: fix cloning + w/new package editor + +2008-06-12 09:56 jeff + + * bin/import-optigold.pl: date fixups + +2008-06-12 08:55 jeff + + * bin/import-optigold.pl: import services from service providing + servers + +2008-06-10 16:24 ivan + + * FS/FS/: Upgrade.pm: start of better error reporting for RADIUS + upgrade errors + +2008-06-10 10:39 ivan + + * FS/FS/Misc.pm: turn off debugging that got left on by accident + +2008-06-09 19:12 ivan + + * httemplate/edit/process/: cust_credit_refund.cgi, + cust_pay_refund.cgi: fix up application of things to refunds, + RT#3606/RT#3545 + +2008-06-09 11:32 ivan + + * FS/FS/cdr.pm: remove name from voxlinesystems2, really + +2008-06-05 15:44 ivan + + * FS/FS/cdr.pm: add am/pm to voxlinesystems2 display format, remove + name, revsere src/dst + +2008-06-05 13:09 ivan + + * FS/FS/: cust_main.pm, part_pkg/flat.pm: fix one-time charge + quantities & + +2008-06-05 12:44 ivan + + * FS/FS/: cust_svc.pm, part_pkg/voip_cdr.pm: disable_src fixes + +2008-06-05 12:29 ivan + + * FS/FS/Schema.pm: unit pricing didn't exist before, so it can be + NULL + +2008-06-05 12:25 ivan + + * FS/FS/part_pkg/flat.pm: implement quantity charging for setup + fees + +2008-06-05 12:24 ivan + + * FS/FS/cdr.pm, FS/FS/cust_main.pm, httemplate/search/cdr.html, + httemplate/view/svc_phone.cgi, httemplate/edit/quick-charge.html, + httemplate/edit/process/quick-charge.cgi: voxlinesystems CDRs and + quantity bs + +2008-06-05 12:06 jeff + + * conf/invoice_html: dash removal + +2008-06-05 10:05 jeff + + * conf/invoice_html: fix unitprice/posttotal nit + +2008-06-05 09:56 jeff + + * conf/invoice_html: fix unitprice/section nit + +2008-06-05 09:51 jeff + + * conf/invoice_html: correct bogus porting + +2008-06-05 05:42 jeff + + * conf/invoice_latex: replace lost braces + +2008-06-05 03:36 ivan + + * FS/FS/cust_main.pm, httemplate/search/cust_main.html, + httemplate/search/report_cust_main.html: add customer status to + adv. customer report, template customer search for future use in + emailing notices, RT#2731 + +2008-06-05 03:34 ivan + + * FS/FS/: cust_pkg.pm: docs for search_sql + +2008-06-05 01:54 ivan + + * httemplate/search/report_cust_bill.html: minor invoice report UI + +2008-06-04 22:06 ivan + + * FS/FS/cust_pay.pm, httemplate/edit/cust_bill_pay.cgi, + httemplate/edit/cust_credit_bill.cgi, + httemplate/edit/cust_pay_refund.cgi, + httemplate/view/cust_main/payment_history/credit.html, + httemplate/view/cust_main/payment_history/payment.html, + httemplate/edit/cust_credit_refund.cgi, + httemplate/edit/elements/ApplicationCommon.html, + httemplate/edit/process/cust_bill_pay.cgi, + httemplate/edit/process/cust_credit_bill.cgi, + httemplate/edit/process/cust_credit_refund.cgi, + httemplate/edit/process/cust_pay_refund.cgi, + httemplate/edit/process/elements/ApplicationCommon.html: payment + and credit applications have separate "apply to refund" choices + now, and no auto-refund choice in the invoice dropdown. RT#3545 + +2008-06-04 15:44 jeff + + * FS/FS/cust_bill.pm: moar tyop + +2008-06-04 15:42 jeff + + * FS/FS/cust_bill.pm: tyop + +2008-06-04 11:50 ivan + + * FS/FS/cust_bill.pm, httemplate/misc/fax-invoice.cgi: this should + fix the random "HylaFax support has not been configured" error, + caused by cust_bill->fax getting called instead of cust_main->fax + field + +2008-06-04 11:40 jeff + + * conf/invoice_html: more voxline invoice formatting + +2008-06-04 11:05 jeff + + * FS/FS/cust_bill.pm: voxline invoice formatting + +2008-06-04 10:57 jeff + + * FS/FS/cdr.pm, FS/FS/cust_bill_pkg.pm, FS/FS/part_pkg/voip_cdr.pm, + conf/invoice_html, conf/invoice_latex, FS/FS/Conf.pm, + FS/FS/Conf_compat17.pm: voxline invoice formatting + +2008-06-04 06:28 jeff + + * FS/FS/: Record.pm, cust_main.pm, tax_rate.pm: tax on tax + +2008-06-04 06:26 jeff + + * FS/FS/Conf.pm, FS/FS/Conf_compat17.pm, FS/FS/cust_bill.pm, + conf/invoice_latex: service address on invoice + +2008-06-03 14:06 ivan + + * FS/FS/cust_bill.pm, FS/FS/Schema.pm, FS/FS/cust_bill_pkg.pm, + FS/FS/cust_pkg.pm, httemplate/search/cust_pkg.cgi, + httemplate/view/cust_main/packages.html: very basic start at + adding quantities + +2008-06-02 11:59 ivan + + * FS/FS/payinfo_transaction_Mixin.pm: fix payinfo_transaction + +2008-06-02 11:31 ivan + + * FS/FS/UI/Web/small_custview.pm: fix ntable calls + +2008-06-02 10:58 ivan + + * httemplate/misc/process/timeworked.html: fix error apply + fractional seconds + +2008-06-02 10:14 ivan + + * FS/FS/UI/Web/small_custview.pm: doh! + +2008-06-02 10:06 ivan + + * FS/FS/CGI.pm, FS/FS/ClientAPI/MyAccount.pm, + FS/FS/UI/Web/small_custview.pm, htetc/handler.pl, + rt/lib/RT/URI/freeside/Internal.pm, + rt/lib/RT/URI/freeside/XMLRPC.pm: badly placed small_custview all + of a sudden causing fatal errors?! wtf + +2008-06-02 04:16 jeff + + * conf/invoice_latex, conf/invoice_latexcoupon, FS/FS/Conf.pm, + FS/FS/Conf_compat17.pm, FS/FS/cust_bill.pm: typeset tear-off + remittance coupon + +2008-06-01 19:47 ivan + + * FS/FS/Misc.pm: and batchmode was probably right + +2008-06-01 19:45 ivan + + * FS/FS/Misc.pm: yow, don't want everything to waitt until the + timeout + +2008-06-01 19:16 ivan + + * FS/FS/: cust_bill.pm, Misc.pm: use IPC::Run to run pslatex & add + a timeout, this should prevent hanging on template errors + +2008-06-01 15:48 ivan + + * FS/FS/cust_pay.pm, FS/FS/cust_refund.pm, FS/FS/payinfo_Mixin.pm, + FS/FS/payinfo_transaction_Mixin.pm, + httemplate/view/cust_main/payment_history.html, + httemplate/search/elements/cust_pay_or_refund.html, + httemplate/view/cust_refund.html, + httemplate/view/cust_main/payment_history/credit.html, + httemplate/view/cust_main/payment_history/invoice.html, + httemplate/view/cust_main/payment_history/payment.html, + httemplate/view/cust_main/payment_history/refund.html, + httemplate/view/cust_main/payment_history/voided_payment.html: + refactor payment history slightly, add refund receipts, have + "unapplied" refunds show like other unapplied/open things, + RT#3545 + +2008-06-01 00:08 ivan + + * FS/FS/cust_pay.pm: show "Check #" on payment receipts instead of + "Billing #" + +2008-05-31 22:43 ivan + + * FS/FS/cust_bill.pm, FS/FS/cust_bill_ApplicationCommon.pm, + httemplate/view/cust_main/payment_history.html: add date to + "applied to Invoice#" messages in history + +2008-05-31 20:19 ivan + + * httemplate/search/cust_bill_pkg.cgi: fix line item report for + agent-virtualized packages, clean up sloppy $where + stringification, hard agent virtualization + +2008-05-31 19:19 jeff + + * bin/import-optigold.pl: umm.. right.. really do some on-demand + stuff + +2008-05-31 18:23 ivan + + * htetc/handler.pl: depend on CGI.pm 3.29 to fix RT attachment + problems + +2008-05-31 17:11 ivan + + * FS/FS/cust_bill.pm: fix problems when service definition names + contain chars that need to be latex escaped + +2008-05-31 16:50 jeff + + * bin/import-optigold.pl: guess at on demand billing, link + pre-existing services + +2008-05-31 10:54 ivan + + * htetc/handler.pl: add an explicit use for RT's not-well-declared + dependency on CSS::Squish 0.06 + +2008-05-31 07:49 jeff + + * FS/FS/cust_bill.pm, conf/invoice_html, conf/invoice_latex: + invoice cosmetic improvements + +2008-05-29 21:04 ivan + + * httemplate/edit/part_bill_event.cgi: 1.7 sucks. but people are + still going to be editing old-style invoice events for a little + while more yet, so space them out better (so options don't run + together) + +2008-05-29 20:55 ivan + + * FS/FS/cust_bill.pm, httemplate/edit/part_bill_event.cgi: 1.7 + sucks. add a "balance over" option to the 1.7 style + agent-specific invoice send event + +2008-05-29 18:38 ivan + + * FS/FS/Misc/prune.pm: fix a missing semicolon bug only triggered + when running prune_applications not in debug mode... + +2008-05-29 18:34 ivan + + * FS/FS/Upgrade.pm: don't print out warnings about SQL RADIUS + FreesideStatus every time either. really? + +2008-05-29 18:33 ivan + + * FS/bin/freeside-upgrade: don't print out the cust_credit_refund + pruning every time + +2008-05-29 18:28 ivan + + * FS/bin/freeside-upgrade: don't print out the cust_credit_refund + pruning every time + +2008-05-29 18:02 ivan + + * FS/FS/cust_pay_pending.pm: clean up any stray/old + cust_pay_pending records causing problems + +2008-05-29 17:53 ivan + + * FS/FS/: Upgrade.pm, cust_pay_pending.pm: clean up any stray/old + cust_pay_pending records causing problems + +2008-05-28 17:11 ivan + + * httemplate/graph/money_time.cgi: line things up better on the + 12mo report (prevent labels from taking up most of the graph + +2008-05-28 03:45 ivan + + * htetc/handler.pl: mailgate realiability fix: don't bomb out when + FS dbdef hasn't been initialized yet (& need to import + adminsuidsetup) + +2008-05-28 03:41 ivan + + * htetc/: handler.pl: mailgate realiability fix: don't bomb out + when FS dbdef hasn't been initialized yet + +2008-05-28 03:14 ivan + + * htetc/handler.pl: mailgate realiability fix: don't bomb out when + FS dbdef hasn't been initialized yet + +2008-05-19 20:52 ivan + + * FS/FS/Upgrade.pm: automatically create an index on the new + radacct.FreesideStatus column + +2008-05-19 15:31 jeff + + * conf/invoice_latex, FS/FS/cust_bill_pkg.pm: fix broken pagenation + +2008-05-19 11:50 ivan + + * FS/FS/Conf.pm: a better link to the T:T docs + +2008-05-18 21:29 ivan + + * FS/FS/Schema.pm: add a key on ( history_action, $primary_key ) to + the h_ tables. this should speed up the cust_pay upgrade?? + +2008-05-18 21:07 ivan + + * FS/FS/cust_bill_pay.pm, FS/FS/payinfo_Mixin.pm, + FS/FS/cust_credit_refund.pm, FS/FS/cust_refund.pm, + FS/FS/payby.pm, FS/FS/Report/Table/Monthly.pm, + httemplate/graph/money_time.cgi, + httemplate/search/cust_bill_pay.html, + httemplate/search/cust_credit.html, + httemplate/search/cust_credit_refund.html, + httemplate/search/cust_pay.cgi, + httemplate/search/cust_refund.html, + httemplate/search/elements/cust_pay_or_refund.html: make net + receipts clickable... and netreceipts != cashflow, really, so + separate those concepts, and cashflow gets gross & net variants. + also add gross/net refunds. #3012 + +2008-05-18 20:51 jeff + + * conf/invoice_latex: fix latex template bogosity + +2008-05-18 15:57 ivan + + * FS/FS/Upgrade.pm: fix auto sqlradius upgrade: module + include/import + +2008-05-18 15:54 ivan + + * FS/FS/part_export/sqlradius.pm: oops, fix minor refactoring of + auto sqlradius upgrade + +2008-05-18 15:53 ivan + + * FS/bin/freeside-upgrade: fix the auto sqlradiusupgrade + +2008-05-18 15:42 ivan + + * FS/FS/Upgrade.pm, FS/bin/freeside-sqlradius-radacctd, + FS/bin/freeside-upgrade, FS/FS/part_export/sqlradius.pm, + init.d/freeside-init: on upgrade, automatically seed from + sqlradius databases, and start freeside-sqlradius-radacctd by + default + +2008-05-17 23:50 ivan + + * FS/FS/Conf.pm, httemplate/edit/process/access_group.html: add a + config value for disabling the ACLs... this should be good for a + demo in 1.7, 1.9 will need some way to disable ACL changes from + OUTSIDE the db + +2008-05-17 20:04 ivan + + * httemplate/: elements/customer-table.html, + misc/batch-cust_pay.html: quick payment entry running total, + closes: #3470 + +2008-05-16 12:26 jeff + + * FS/FS/Schema.pm, FS/FS/cdr.pm, FS/FS/cust_bill.pm, + FS/FS/cust_bill_pkg.pm, FS/FS/cust_bill_pkg_detail.pm, + FS/FS/part_pkg/voip_cdr.pm, conf/invoice_html, + conf/invoice_latex: typeset CDRs into 5 columns on invoices + +2008-05-15 15:48 ivan + + * FS/FS/CGI.pm: fix minor problem with ship_zip not showing up in + small_custview + +2008-05-14 14:21 jeff + + * FS/FS/: Conf.pm, Conf_compat17.pm, cust_bill.pm: config option to + omit statement type items from invoices + +2008-05-14 11:19 jeff + + * bin/import-optigold.pl: do NOT delete the existing data + +2008-05-14 11:07 jeff + + * FS/FS/: cust_bill_pkg.pm, part_pkg.pm, tax_rate.pm, + part_pkg/voip_cdr.pm: correct tax selection and *actually* handle + fee based taxes + +2008-05-14 09:52 ivan + + * bin/import-optigold.pl: [no log message] + +2008-05-13 16:36 ivan + + * FS/bin/freeside-adduser: tyop + +2008-05-13 14:20 ivan + + * FS/FS/part_pkg.pm: eliminate warnings on upgrade: "(Odd number of + elements in anonymous hash | Use of unintialized value in + anonymous hash ) at + /usr/local/share/perl/5.8.8/FS/option_Common.pm line 176. + +2008-05-13 12:13 ivan + + * Makefile: ensure new self-service libs are installed + +2008-05-12 20:49 ivan + + * debian/rules: tyop + +2008-05-12 20:49 ivan + + * Makefile, FS/bin/freeside-setup, debian/rules: better place for + initial configuration to be stored and retreived from than the + initial tarball... + +2008-05-08 23:34 ivan + + * httemplate/misc/: xmlhttp-cust_main-address_standardize.html, + xmlhttp-cust_main-search.cgi: JSON 1.0 (on deb 4.0) doesn't have + to_json yet + +2008-05-08 22:59 ivan + + * httemplate/: docs/credits.html, docs/license.html, + edit/cust_main.cgi, images/cross.png, images/error.png, + images/tick.png: finish usps address standardization + +2008-05-08 22:54 ivan + + * httemplate/view/cust_main/packages.html: perl 5.10-ism? new + mason? + +2008-05-08 05:45 ivan + + * FS/FS/Conf.pm, httemplate/edit/cust_main.cgi, + httemplate/elements/xmlhttp.html, + httemplate/misc/xmlhttp-cust_main-address_standardize.html, + httemplate/misc/xmlhttp-cust_main-search.cgi, htetc/handler.pl: + address standardization part one, finally checked in from here + +2008-05-07 14:36 ivan + + * httemplate/: view/cust_main.cgi, misc/cancel_cust.html: fix + customer cancellation, sort of a side effect of #2872, fixes + #3480, #3481 + +2008-05-05 18:15 ivan + + * httemplate/elements/customer-table.html: put the documentation in + a proper <%doc> section + +2008-05-05 18:14 ivan + + * httemplate/misc/xmlhttp-cust_main-search.cgi: agent-virtualize + customer # portion of quick payment entry + +2008-05-05 18:14 ivan + + * httemplate/: misc/batch-cust_pay.html, + elements/customer-table.html: agent-virtualize quick payment + entry + +2008-05-04 19:11 ivan + + * FS/FS/payinfo_Mixin.pm: hopefully really a better fix for using + new payment duplicate stuff with cc encryption :/ + +2008-05-04 18:52 ivan + + * FS/FS/payinfo_Mixin.pm: better fix for using new payment + duplicate stuff with cc encryption :) + +2008-05-04 18:18 ivan + + * FS/FS/payinfo_Mixin.pm: fix for using new payment duplicate stuff + with cc encryption + +2008-05-02 13:30 ivan + + * FS/bin/freeside-upgrade: add -s switch to freeside-upgrade for + schema-only changes (for slony slaves) + +2008-05-01 18:58 ivan + + * FS/FS/Upgrade.pm: upgrade part_pkg before cust_credit + +2008-04-30 16:42 ivan + + * Makefile: not here + +2008-04-30 16:36 ivan + + * Makefile: that explains the bs with ChangeLog + +2008-04-30 16:29 ivan + + * Makefile: last last-minute fix for last-minute change + +2008-04-30 16:26 ivan + + * Makefile: last minute fix for last minute change + +2008-04-30 16:19 ivan + + * Makefile: last minute release target update. not particularly + dangerous, nobody uses it but me + +2008-04-28 12:17 ivan + + * FS/FS/: cust_main.pm, Cron/bill.pm: fix 1.9 queued billing from + doing weird things with expirations and adjournments because + freeside-queued $^T != freeside-daily $^T + +2008-04-27 09:28 jeff + + * httemplate/elements/select-taxproduct.html: sticky, too + +2008-04-27 08:19 jeff + + * httemplate/elements/select-taxproduct.html: fixup taxproduct + selection + +2008-04-24 15:51 ivan + + * FS/FS/part_pkg/voip_cdr.pm: add use_amaflags and use_disposition + flags to voip_cdr price plan + +2008-04-22 19:59 jeff + + * FS/FS/cust_bill.pm: fixup return address fallback + +2008-04-22 12:46 ivan + + * FS/FS/cust_bill.pm: no comma there + +2008-04-22 03:56 ivan + + * FS/FS/: cdr.pm, part_pkg/voip_cdr.pm: voxline cdrs + +2008-04-18 14:27 ivan + + * rt/lib/RT/Ticket_Overlay.pm: blah. last silly typo hopefully. + wish this was easier to test. + +2008-04-18 14:25 ivan + + * rt/lib/RT/Ticket_Overlay.pm: silly semicolon + +2008-04-18 14:19 ivan + + * rt/lib/RT/: Ticket_Overlay.pm, URI/freeside.pm: hopefully, + finally fix ticket auto-association not getting along with RT + ACLs + +2008-04-17 20:29 jeff + + * FS/t/addr_block.t, FS/t/router.t, httemplate/edit/allocate.html, + httemplate/browse/addr_block.cgi, httemplate/browse/router.cgi, + httemplate/edit/process/addr_block/add.cgi, + httemplate/edit/process/addr_block/allocate.cgi, + httemplate/edit/process/addr_block/deallocate.cgi, + httemplate/edit/process/addr_block/split.cgi: drag address and + router even farther into the century + +2008-04-16 18:39 ivan + + * FS/FS/: Schema.pm, cust_bill.pm, cust_bill_pkg.pm, cust_main.pm, + cust_main_county.pm, cust_pkg.pm, part_pkg/flat.pm: implement + line item bundling + +2008-04-16 18:28 ivan + + * httemplate/elements/menu.html: this is more accurate + +2008-04-16 14:52 ivan + + * FS/FS/: part_pkg.pm, cust_main.pm: start implementing billing + add-ons + +2008-04-16 14:12 ivan + + * FS/FS/part_pkg.pm, httemplate/browse/part_pkg.cgi: implement + service add-ons + +2008-04-16 14:10 ivan + + * FS/FS/Record.pm: be more forgiving about numeric things padded + with leading/trailing space + +2008-04-16 13:34 ivan + + * httemplate/: edit/part_bill_event.cgi, edit/part_pkg.cgi, + edit/quick-charge.html, elements/select-taxclass.html, + elements/tr-select-taxclass.html: fix tax class on package def + edit + +2008-04-16 13:00 ivan + + * httemplate/: browse/part_pkg.cgi, edit/part_pkg.cgi: show package + add-on links in browse + +2008-04-16 11:32 jeff + + * FS/FS/cust_pkg.pm, FS/FS/cust_pkg_reason.pm, + httemplate/view/cust_main/packages.html: show user who created + (cancel/suspend) reason and possibly fix a lingering spurious + usergroup bug + +2008-04-16 04:54 jeff + + * httemplate/edit/part_pkg_taxproduct.html: this no longer belongs + +2008-04-15 21:42 ivan + + * httemplate/: edit/part_pkg.cgi, browse/part_pkg.cgi: add plan & + pricing to package browse... + +2008-04-15 18:03 ivan + + * FS/FS/m2m_Common.pm, FS/FS/part_pkg.pm, + httemplate/edit/process/part_pkg.cgi: fix new link editing in new + package editor + +2008-04-15 17:29 ivan + + * FS/FS/part_pkg.pm: new package def editor + +2008-04-15 17:19 ivan + + * httemplate/edit/: part_pkg.cgi, elements/edit.html, + process/part_pkg.cgi: new package def editor + +2008-04-15 17:16 ivan + + * FS/: FS.pm, FS/m2m_Common.pm, FS/part_pkg_link.pm, + t/part_pkg_link.t: new package def editor + +2008-04-15 13:47 jeff + + * httemplate/elements/file-upload.html, + httemplate/elements/header-minimal.html, + httemplate/misc/file-upload.html, httemplate/misc/tax-import.cgi, + httemplate/misc/process/tax-import.cgi, + httemplate/misc/process/tax-upgrade.cgi, FS/FS/cust_main.pm, + FS/FS/cust_tax_location.pm, FS/FS/part_pkg.pm, + FS/FS/part_pkg_taxproduct.pm, FS/FS/part_pkg_taxrate.pm, + FS/FS/tax_class.pm, FS/FS/tax_rate.pm: (finally) wrap up new tax + rate engine (for now) + +2008-04-15 12:43 ivan + + * FS/FS/: part_pkg_option.pm, part_pkg/sesmon_hour.pm, + part_pkg/sesmon_minute.pm, part_pkg/sql_external.pm, + part_pkg/sql_generic.pm, part_pkg/sqlradacct_hour.pm, + part_pkg/voip_cdr.pm, part_pkg/voip_sqlradacct.pm: + s/recur_flat/recur_fee/ + +2008-04-15 06:41 ivan + + * FS/FS/Schema.pm, FS/FS/cust_event.pm, FS/FS/cust_main.pm, + FS/FS/cust_pkg.pm, FS/FS/option_Common.pm, + FS/FS/part_event_option.pm, FS/FS/part_pkg.pm, + FS/FS/svc_Common.pm, FS/FS/svc_acct.pm, FS/FS/svc_domain.pm, + httemplate/edit/part_event.html, httemplate/edit/part_pkg.cgi, + httemplate/edit/elements/edit.html, + httemplate/edit/process/part_pkg.cgi, + httemplate/edit/process/elements/process.html, + httemplate/elements/select-agent_types.html, + httemplate/elements/select-taxproduct.html, + httemplate/elements/selectlayers.html, + httemplate/elements/tr-input-text.html, + httemplate/elements/tr-part_pkg_freq.html, + httemplate/elements/tr-pkg_svc.html, + httemplate/elements/tr-select-agent_types.html, + httemplate/elements/tr-title.html: new package editor + +2008-04-15 03:50 ivan + + * httemplate/docs/about.html: it's april 15th, and i sure do. + +2008-04-14 06:42 jeff + + * FS/FS/Record.pm: Improve record searching + +2008-04-13 14:37 ivan + + * FS/FS/part_pkg/: base_delayed.pm, flat_delayed.pm, + prorate_delayed.pm: fix recur_notify label for *_delayed price + plans + +2008-04-13 13:35 ivan + + * httemplate/elements/: select-cust-part_pkg.html, + select-part_pkg.html, tr-select-part_pkg.html, select-table.html: + select-table and select-part_pkg updates so we can use + select-part_pkg as an edit/elements/edit.html m2 type + +2008-04-13 03:21 ivan + + * httemplate/elements/tr-justtitle.html: adding just a title with + no blank space above + +2008-04-13 03:19 ivan + + * httemplate/elements/: tr-selectlayers-select.html, + selectlayers.html: add a tr- for just the select bit of a + selectlayers... + +2008-04-13 01:21 ivan + + * httemplate/elements/tr-input-text.html: add disabled option to + text elements + +2008-04-13 00:41 ivan + + * FS/FS/part_pkg/: base_delayed.pm, base_rate.pm, bulk.pm, flat.pm, + flat_comission.pm, flat_comission_cust.pm, flat_comission_pkg.pm, + flat_delayed.pm, flat_introrate.pm, prepaid.pm, prorate.pm, + prorate_delayed.pm, sesmon_hour.pm, sesmon_minute.pm, + sql_external.pm, sql_generic.pm, sqlradacct_hour.pm, + subscription.pm, voip_cdr.pm, voip_sqlradacct.pm: shorter names + and rearranged weights for a brighter tommorow^W^Wbetter price + plan if there's none or + one - signup_server-realtime config option to run billing for + signup server signups immediately - signup server: pkg + available to success templates, better documentation on success + templates - httemplate/edit/msgcat.cgi fields are properly sticky + on errors - httemplate/edit/process/msgcat.cgi - don't update + identical fields + +2002-04-10 01:39 ivan + + * bin/fs-setup: fix mistake in part_pop_local schema (not used by + anyone really so no big deal) + +2002-04-06 22:23 ivan + + * FS/FS/: Conf.pm, cust_bill.pm, cust_pay.pm: send email on signup + server signups (closes: Bug#386) + +2002-04-06 21:56 ivan + + * FS/FS/Conf.pm, FS/FS/msgcat.pm, bin/populate-msgcat, + conf/show-msgcat-codes, httemplate/browse/msgcat.cgi, + httemplate/docs/install.html, httemplate/edit/msgcat.cgi, + httemplate/edit/process/msgcat.cgi: working message catalogs (not + used for enough yet) - almost (but not quite) closes Bug#385 - + still have to catalog the backend things triggered by signup + server. + +2002-04-06 16:00 ivan + + * FS/FS/Conf.pm, httemplate/config/config-process.cgi, + httemplate/config/config-view.cgi, httemplate/config/config.cgi, + httemplate/docs/signup.html: - config option for signup server + payment types - credit card type pulldown on signup server + (closes: Bug#383) + +2002-04-06 14:32 ivan + + * FS/FS/: Conf.pm, cust_bill.pm, cust_bill_pkg.pm, cust_main.pm: + add a config option to set the Business::OnlinePayment + description field, and make some useful data available for the + config option. closes: Bug#378 + +2002-04-06 13:32 ivan + + * httemplate/search/cust_main.cgi: fix visual glitch + +2002-04-06 12:37 ivan + + * httemplate/docs/: install.html, signup.html: big signup server + cleanups. uses Storable for network protocol now. - makes Bugs + 384 & 385 easier - closes: Bug#382 + +2002-04-05 16:08 ivan + + * FS/FS/svc_acct.pm, httemplate/edit/svc_acct.cgi, + httemplate/view/svc_acct.cgi: security phrase bug fixes + +2002-04-05 15:51 ivan + + * ANNOUCE.1.4.0, CREDITS, Makefile, README.1.4.0pre12, FS/MANIFEST, + FS/FS/Conf.pm, FS/FS/msgcat.pm, FS/FS/svc_acct.pm, FS/t/msgcat.t, + bin/freeside-session-kill, bin/fs-setup, bin/populate-msgcat, + bin/sqlradius_reset, conf/locale, eg/table_template-svc.pm, + eg/table_template.pm, htetc/global.asa, htetc/handler.pl, + httemplate/index.html, httemplate/browse/cust_main_county.cgi, + httemplate/browse/msgcat.cgi, + httemplate/browse/part_referral.cgi, + httemplate/browse/svc_acct_pop.cgi, httemplate/docs/schema.html, + httemplate/docs/upgrade8.html, httemplate/edit/svc_acct.cgi, + httemplate/view/svc_acct.cgi: - add message catalog table & + beginning of web interface - add security_phrase and conf option + to svc_acct.pm - random other stuff + +2002-04-05 15:37 jeff + + * httemplate/view/cust_main.cgi: credit/refund display correction + +2002-04-05 12:52 ivan + + * httemplate/edit/process/cust_credit_bill.cgi: don't specify date + (not on submitting form) + +2002-04-05 08:37 ivan + + * eg/export_template.pm, httemplate/search/sql.cgi, + FS/t/part_export-infostreet.t, FS/t/part_export-sqlradius.t: oops + forgot these from working on the road + +2002-04-04 16:42 ivan + + * FS/MANIFEST, FS/FS/part_export.pm, + FS/FS/part_export/infostreet.pm, FS/FS/part_export/sqlradius.pm, + httemplate/index.html, httemplate/docs/install.html, + httemplate/edit/part_export.cgi: Checkin of disparate changes + from working on the road: - generic SQL query - move exports out + to their own files - small cleanup of selfadmin server + +2002-03-29 18:35 ivan + + * httemplate/edit/part_referral.cgi: finish up + s/referral/advertising source/ + +2002-03-29 09:27 ivan + + * htetc/global.asa, htetc/handler.pl, + httemplate/search/svc_acct.cgi: fix unlinked svc browse! + +2002-03-27 16:18 ivan + + * ANNOUCE.1.4.0: still pretty much just notes... + +2002-03-26 23:08 ivan + + * FS/FS/queue.pm: don't show queue arguments (passwords!) on svc_* + screens (unless queue_dangerous_options!) + +2002-03-26 21:36 ivan + + * FS/FS/cust_main.pm, FS/FS/part_referral.pm, + httemplate/index.html, httemplate/browse/part_referral.cgi, + httemplate/docs/admin.html, httemplate/edit/part_referral.cgi: + s/referral/advertising source/ + + yes, the name sucks. got a better one? + +2002-03-26 15:18 ivan + + * fs_passwd/fs_passwd.cgi: yay works now... just forgot to send + http header + +2002-03-26 08:24 ivan + + * httemplate/search/cust_main.cgi: simple visual fix:   for + blank company column + +2002-03-26 05:58 ivan + + * FS/FS/part_svc.pm: forgot to use FS::part_export to search on it + +2002-03-26 05:20 ivan + + * httemplate/docs/passwd.html: doc + +2002-03-26 05:04 ivan + + * bin/create-history-tables: error message typo + +2002-03-26 04:35 ivan + + * httemplate/docs/admin.html: s/Add/Provision/ + +2002-03-25 16:32 ivan + + * FS/FS/part_export.pm, FS/bin/freeside-queued, + bin/sqlradius_reset, httemplate/edit/part_export.cgi: further + export bugfixing add 10 kid limit to freeside-queued + sqlradius_reset now works (closes: Bug#372) + +2002-03-25 16:26 ivan + + * Makefile: hhahah oops i _really_ ought to do something about that + +2002-03-25 06:59 ivan + + * httemplate/: index.html, search/cust_main-otaker.cgi, + search/cust_main.cgi: customers by otaker report (ugly + search/cust_main.cgi mods; revert if they cause problems) + +2002-03-24 15:16 ivan + + * bin/: icradius_reset, sqlradius_reset: s/icradius/sqlradius/ + +2002-03-24 12:00 ivan + + * httemplate/: edit/cust_main.cgi, search/svc_acct.cgi, + browse/agent.cgi: UI improvements for agents + +2002-03-24 10:23 ivan + + * FS/FS/agent.pm: tyop + +2002-03-24 09:42 ivan + + * CREDITS, FS/FS/part_pkg.pm, httemplate/edit/part_pkg.cgi: + "subscription" price plan from "Luke Pfeifer" + + +2002-03-24 06:29 ivan + + * FS/FS/Conf.pm, FS/FS/part_export.pm, FS/FS/queue.pm, + FS/FS/radius_usergroup.pm, FS/FS/svc_acct.pm, + httemplate/edit/svc_acct.cgi: + ICRADIUS groups all done! UI and provisioning. closes: Bug#362 + + fix some bugs in the export and add queue_dangerous_controls + option too + +2002-03-23 09:49 ivan + + * FS/FS/part_svc.pm, FS/FS/svc_acct.pm, + httemplate/browse/part_svc.cgi, httemplate/edit/part_svc.cgi, + httemplate/edit/process/part_svc.cgi: okay group editing UI as + well as part_svc group editing UI seem to be working + +2002-03-23 08:16 ivan + + * FS/FS/part_export.pm, FS/FS/queue.pm, FS/FS/svc_acct.pm, + httemplate/edit/svc_acct.cgi, + httemplate/edit/process/svc_acct.cgi: group editing seems to be + working... everything except defaults... oh and export... + +2002-03-22 23:54 ivan + + * FS/bin/freeside-queued: redirect STDOUT/STDERR a bit later for + better error reporting + +2002-03-22 10:56 ivan + + * Makefile, README.1.4.0pre12, FS/MANIFEST, + FS/FS/cust_main_county.pm, FS/FS/svc_acct.pm, + FS/t/radius_usergroup.t, bin/create-history-tables, bin/fs-setup, + httemplate/docs/schema.html, httemplate/docs/upgrade8.html, + httemplate/edit/part_svc.cgi, httemplate/edit/svc_acct.cgi, + httemplate/view/svc_acct.cgi: RADIUS groups on the way! + +2002-03-22 04:49 ivan + + * FS/MANIFEST, FS/FS/Record.pm, FS/FS/part_export.pm, + FS/t/part_export.t, FS/t/part_export_option.t, + httemplate/browse/part_svc.cgi, httemplate/edit/part_export.cgi, + httemplate/edit/process/part_export.cgi, + httemplate/misc/delete-part_export.cgi: more new export... + +2002-03-20 22:57 ivan + + * FS/FS/part_export.pm, httemplate/edit/part_export.cgi, + httemplate/edit/process/part_export.cgi: more for the new world + of export... + +2002-03-20 13:31 ivan + + * README.1.4.0pre12, FS/FS/Conf.pm, FS/FS/part_export.pm, + FS/FS/part_export_option.pm, FS/FS/part_svc.pm, + FS/FS/svc_acct.pm, FS/bin/freeside-queued, bin/icradius_reset, + bin/svc_acct.export, htetc/global.asa, htetc/handler.pl, + httemplate/docs/export.html, httemplate/docs/upgrade8.html, + httemplate/edit/part_export.cgi, + httemplate/edit/process/part_export.cgi: new export! infostreet + and sqlradius provisioning switched over (Bug #299 - doesn't + close it, but all the groundwork is done) + + also removes non-transactional ICRADIUS export from + svc_acct.export (closes: Bug#347) + +2002-03-19 23:37 ivan + + * FS/FS/cust_main_county.pm: disable region caching for now + +2002-03-19 09:48 ivan + + * FS/FS/cust_main_county.pm, httemplate/edit/cust_main.cgi, + httemplate/edit/process/cust_main.cgi: changes dum big + "state/county/country" select to three, linked with javascript + closes: Bug#353 + +2002-03-18 13:40 ivan + + * FS/FS/: Conf.pm, cust_bill.pm, part_bill_event.pm: bugfixes, + closes Bug#314 + +2002-03-18 12:50 ivan + + * httemplate/edit/part_bill_event.cgi, FS/FS/part_bill_event.pm, + FS/FS/Conf.pm: okay, now you can specify an alternate invoice + template, and it'll be auto-createad and added to the list of + configuration options. closes: Bug#314 + +2002-03-18 11:49 ivan + + * FS/FS/: Conf.pm, Record.pm, cust_bill.pm, cust_pay.pm: fixes: bug + #348 - adds the ability to email on deleted payments. + +2002-03-18 11:40 ivan + + * httemplate/search/cust_main-quickpay.html: update quickpay for + current search capabilities + +2002-03-18 09:50 ivan + + * httemplate/config/config.cgi: + fixes bug#367 (yay, that one was annoying): + + in config editor, initial newlines in @@ -19,6 +21,9 @@ my $onchange = $opt{'onchange'} ? 'onChange="'. $opt{'onchange'}. '(this)"' : ''; +my $rows = $opt{'rows'} ? 'ROWS="'.$opt{'rows'}.'"' : ''; +my $cols = $opt{'cols'} ? 'COLS="'.$opt{'cols'}.'"' : ''; + my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : ''; my $curr_value = $opt{'curr_value'}; -- cgit v1.2.1 From 3501246417cacd5614a32ac1fe487a230ebb632d Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:45:24 +0000 Subject: end form --- httemplate/search/report_cdr.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/httemplate/search/report_cdr.html b/httemplate/search/report_cdr.html index f3ad1e69f..c685198d9 100644 --- a/httemplate/search/report_cdr.html +++ b/httemplate/search/report_cdr.html @@ -115,6 +115,8 @@
    + + <% include('/elements/footer.html') %> <%init> -- cgit v1.2.1 From ed6084d4ccabb81493ffa1ee42c2afd237c05f45 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:45:53 +0000 Subject: don't try to follow a blank redirect --- httemplate/search/elements/search-html.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/httemplate/search/elements/search-html.html b/httemplate/search/elements/search-html.html index 60dd65a5c..297774dfd 100644 --- a/httemplate/search/elements/search-html.html +++ b/httemplate/search/elements/search-html.html @@ -1,5 +1,6 @@ % -% if ( exists($opt{'redirect'}) && scalar(@$rows) == 1 && $total == 1 +% if ( exists($opt{'redirect'}) && $opt{'redirect'} +% && scalar(@$rows) == 1 && $total == 1 % && $type ne 'html-print' % ) { % my $redirect = $opt{'redirect'}; -- cgit v1.2.1 From ad8f95a4fa225465436e5e9d77bb3ab09b0fa931 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:46:43 +0000 Subject: huh --- rt/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rt/Makefile b/rt/Makefile index e6a5ddee5..7d510c81b 100644 --- a/rt/Makefile +++ b/rt/Makefile @@ -60,7 +60,7 @@ SITE_CONFIG_FILE = $(CONFIG_FILE_PATH)/RT_SiteConfig.pm RT_VERSION_MAJOR = 3 RT_VERSION_MINOR = 6 -RT_VERSION_PATCH = 4 +RT_VERSION_PATCH = 6 RT_VERSION = $(RT_VERSION_MAJOR).$(RT_VERSION_MINOR).$(RT_VERSION_PATCH) TAG = rt-$(RT_VERSION_MAJOR)-$(RT_VERSION_MINOR)-$(RT_VERSION_PATCH) @@ -83,7 +83,7 @@ WEB_USER = freeside WEB_GROUP = freeside -APACHECTL = /usr/sbin/apachectl +APACHECTL = # {{{ Files and directories -- cgit v1.2.1 From 8166c86a5e6312f88e84f9d9107ef11a99bf8545 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:48:25 +0000 Subject: huh #2 --- rt/lib/RT.pm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rt/lib/RT.pm b/rt/lib/RT.pm index 0d0c0f509..22fb9a11c 100644 --- a/rt/lib/RT.pm +++ b/rt/lib/RT.pm @@ -68,7 +68,7 @@ use vars qw($VERSION $System $SystemUser $Nobody $Handle $Logger $MasonSessionDir ); -$VERSION = '3.6.4'; +$VERSION = '3.6.6'; $CORE_CONFIG_FILE = "/opt/rt3/etc/RT_Config.pm"; $SITE_CONFIG_FILE = "/opt/rt3/etc/RT_SiteConfig.pm"; @@ -161,12 +161,12 @@ EOF } eval { require $CORE_CONFIG_FILE }; if ($@) { - my ($fileuid,$filegid) = (stat($SITE_CONFIG_FILE))[4,5]; + my ($fileuid,$filegid) = (stat($CORE_CONFIG_FILE))[4,5]; my $fileusername = getpwuid($fileuid); my $filegroup = getgrgid($filegid); - my $errormessage = sprintf($message, $SITE_CONFIG_FILE, + my $errormessage = sprintf($message, $CORE_CONFIG_FILE, $fileusername, $filegroup, $filegroup); - die ("$errormessage '$CORE_CONFIG_FILE'\n$@") + die ("$errormessage\n$@") } # RT::Essentials mistakenly recommends that WebPath be set to '/'. @@ -459,6 +459,8 @@ ok ($RT::SystemUser->Name() ne 'noname', "The system user isn't noname"); =cut +eval "require RT_Vendor"; +die $@ if ($@ && $@ !~ qr{^Can't locate RT_Vendor.pm}); eval "require RT_Local"; die $@ if ($@ && $@ !~ qr{^Can't locate RT_Local.pm}); -- cgit v1.2.1 From 325af2363cc1ebbc8479342c4e97eb2a59b05aa4 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:48:38 +0000 Subject: do it --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 79135e7a7..ee75ea4cf 100644 --- a/Makefile +++ b/Makefile @@ -123,8 +123,8 @@ RT_PATH = /opt/rt3 FREESIDE_PATH = `pwd` PERL_INC_DEV_KLUDGE = /usr/local/share/perl/5.10.0/ -VERSION=1.9.0cvs -TAG=freeside_1_9_0 +VERSION=1.9.1 +TAG=freeside_1_9_1 DEBVERSION = `echo ${VERSION} | perl -pe 's/(\d)([a-z])/\1~\2/'`-1 -- cgit v1.2.1 From 776a58122174269f1706989af74617deece59fa2 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:50:43 +0000 Subject: helps to have the tool --- Makefile | 2 +- bin/cvs2cl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100755 bin/cvs2cl diff --git a/Makefile b/Makefile index ee75ea4cf..82e6cb214 100644 --- a/Makefile +++ b/Makefile @@ -389,7 +389,7 @@ clean: .PHONY: release release: # Update the changelog - ./CVS2CL + ./bin/cvs2cl cvs commit -m "Updated for ${VERSION}" ChangeLog # Update the RPM specfile diff --git a/bin/cvs2cl b/bin/cvs2cl new file mode 100755 index 000000000..442bf56dd --- /dev/null +++ b/bin/cvs2cl @@ -0,0 +1 @@ +cvs2cl -F trunk -- cgit v1.2.1 From 455f6852d63fca4f9e572be5c2401a9b5fdc05cd Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:51:41 +0000 Subject: helps to have the tool --- bin/cvs2cl | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/cvs2cl b/bin/cvs2cl index 442bf56dd..1c1bfb097 100755 --- a/bin/cvs2cl +++ b/bin/cvs2cl @@ -1 +1,2 @@ +#!/bin/sh cvs2cl -F trunk -- cgit v1.2.1 From 8a8bca8c782c7213d660f8244105654f2863e2c7 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 01:58:16 +0000 Subject: Updated for 1.9.1 --- ChangeLog | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- debian/changelog | 6 ++ rpm/freeside.spec | 2 +- 3 files changed, 203 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index e3de770a2..48270b5ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,64 @@ +2009-10-10 18:50 ivan + + * Makefile, bin/cvs2cl: helps to have the tool + +2009-10-10 18:48 ivan + + * Makefile: do it + +2009-10-10 18:48 ivan + + * rt/lib/RT.pm: huh #2 + +2009-10-10 18:46 ivan + + * rt/Makefile: huh + +2009-10-10 18:45 ivan + + * httemplate/search/elements/search-html.html: don't try to follow + a blank redirect + +2009-10-10 18:45 ivan + + * httemplate/search/report_cdr.html: end form + +2009-10-10 18:45 ivan + + * httemplate/elements/tr-textarea.html: new rows and cols options + +2009-10-10 18:44 ivan + + * httemplate/elements/tr-select-pkg_class.html: respect + element_name + +2009-10-10 18:43 ivan + + * httemplate/browse/agent.cgi: cleanup + +2009-10-10 18:42 ivan + + * eg/cdr_template.pm, httemplate/elements/selectlayers.html: doc + +2009-10-10 18:41 ivan + + * FS/FS/part_export/globalpops_voip.pm: correct variable + initialization + +2009-10-10 18:40 ivan + + * FS/FS/: access_right.pm, access_usergroup.pm, + clientapi_session_field.pm, cust_svc_option.pm: remembered to + customize this manpage + +2009-10-10 18:39 ivan + + * FS/FS/Record.pm: ::1 becomes 127.0.0.1 in IP checks + +2009-10-09 20:22 ivan + + * ChangeLog: commit message for a file about commitmessages + 2009-10-09 16:59 ivan * FS/FS/Schema.pm, FS/FS/cust_main.pm, @@ -23658,6 +23719,11 @@ * FS/FS/cust_pkg.pm: add last_bill field to manpage +2003-05-30 02:40 ivan + + * httemplate/docs/man/FS/part_export/.cvs_is_on_crack: force + inclusion of httemplate/docs/man hierarchy + 2003-05-30 02:22 ivan * FS/FS/part_export/sqlradius.pm: sqlradius exports include "op" @@ -28215,6 +28281,10 @@ * httemplate/docs/install.html: doc update +2002-02-04 09:12 ivan + + * httemplate/docs/man/FS/: Bill.html, Invoice.html: ancient files + 2002-02-04 09:06 ivan * Makefile, README.1.4.0pre4567-8, README.1.4.0pre8: 1.4.0pre8! @@ -28303,11 +28373,60 @@ new CGI; &cgisuidsetup(); from all templates. should work better under Mason. +2002-01-29 09:46 ivan + + * httemplate/docs/man/: FS.html, FS/CGI.html, FS/CGIwrapper.html, + FS/Conf.html, FS/Record.html, FS/SessionClient.html, + FS/SignupClient.html, FS/UID.html, FS/agent.html, + FS/agent_type.html, FS/cust_bill.html, FS/cust_bill_pkg.html, + FS/cust_credit.html, FS/cust_main.html, FS/cust_main_county.html, + FS/cust_main_invoice.html, FS/cust_pay.html, + FS/cust_pay_batch.html, FS/cust_pkg.html, FS/cust_refund.html, + FS/cust_svc.html, FS/domain_record.html, FS/nas.html, + FS/part_pkg.html, FS/part_referral.html, FS/part_svc.html, + FS/pkg_svc.html, FS/port.html, FS/prepay_credit.html, + FS/session.html, FS/svc_Common.html, FS/svc_acct.html, + FS/svc_acct_pop.html, FS/svc_acct_sm.html, FS/svc_domain.html, + FS/svc_www.html, FS/type_pkgs.html: these are all auto-generated + by the installation; don't check them into CVS (probably should + generate them for a release tarball though) + 2002-01-29 09:42 ivan * README.1.4.0pre4567-8, FS/FS/part_bill_event.pm, bin/fs-setup, - httemplate/docs/schema.html, httemplate/docs/upgrade8.html: - weight, plan and plandata fields in part_bill_event + httemplate/docs/schema.html, httemplate/docs/upgrade8.html, + httemplate/docs/man/FS/SessionClient.html, + httemplate/docs/man/FS/UID.html, + httemplate/docs/man/FS/agent.html, + httemplate/docs/man/FS/agent_type.html, + httemplate/docs/man/FS/cust_bill.html, + httemplate/docs/man/FS/cust_bill_pkg.html, + httemplate/docs/man/FS/cust_credit.html, + httemplate/docs/man/FS/cust_main.html, + httemplate/docs/man/FS/cust_main_county.html, + httemplate/docs/man/FS/cust_main_invoice.html, + httemplate/docs/man/FS/cust_pay.html, + httemplate/docs/man/FS/cust_pay_batch.html, + httemplate/docs/man/FS/cust_pkg.html, + httemplate/docs/man/FS/cust_refund.html, + httemplate/docs/man/FS/cust_svc.html, + httemplate/docs/man/FS/domain_record.html, + httemplate/docs/man/FS/nas.html, + httemplate/docs/man/FS/part_pkg.html, + httemplate/docs/man/FS/part_referral.html, + httemplate/docs/man/FS/part_svc.html, + httemplate/docs/man/FS/pkg_svc.html, + httemplate/docs/man/FS/port.html, + httemplate/docs/man/FS/prepay_credit.html, + httemplate/docs/man/FS/session.html, + httemplate/docs/man/FS/svc_Common.html, + httemplate/docs/man/FS/svc_acct.html, + httemplate/docs/man/FS/svc_acct_pop.html, + httemplate/docs/man/FS/svc_acct_sm.html, + httemplate/docs/man/FS/svc_domain.html, + httemplate/docs/man/FS/svc_www.html, + httemplate/docs/man/FS/type_pkgs.html: weight, plan and plandata + fields in part_bill_event 2002-01-29 08:33 ivan @@ -28315,7 +28434,42 @@ FS/FS/cust_pay.pm, FS/FS/cust_pkg.pm, FS/FS/cust_svc.pm, FS/FS/svc_acct.pm, bin/pod2x, htetc/global.asa, htetc/handler.pl, httemplate/index.html, httemplate/browse/part_bill_event.cgi, - httemplate/docs/install.html, + httemplate/docs/install.html, httemplate/docs/man/FS.html, + httemplate/docs/man/FS/CGI.html, + httemplate/docs/man/FS/Conf.html, + httemplate/docs/man/FS/Record.html, + httemplate/docs/man/FS/SessionClient.html, + httemplate/docs/man/FS/SignupClient.html, + httemplate/docs/man/FS/UID.html, + httemplate/docs/man/FS/agent.html, + httemplate/docs/man/FS/agent_type.html, + httemplate/docs/man/FS/cust_bill.html, + httemplate/docs/man/FS/cust_bill_pkg.html, + httemplate/docs/man/FS/cust_credit.html, + httemplate/docs/man/FS/cust_main.html, + httemplate/docs/man/FS/cust_main_county.html, + httemplate/docs/man/FS/cust_main_invoice.html, + httemplate/docs/man/FS/cust_pay.html, + httemplate/docs/man/FS/cust_pay_batch.html, + httemplate/docs/man/FS/cust_pkg.html, + httemplate/docs/man/FS/cust_refund.html, + httemplate/docs/man/FS/cust_svc.html, + httemplate/docs/man/FS/domain_record.html, + httemplate/docs/man/FS/nas.html, + httemplate/docs/man/FS/part_pkg.html, + httemplate/docs/man/FS/part_referral.html, + httemplate/docs/man/FS/part_svc.html, + httemplate/docs/man/FS/pkg_svc.html, + httemplate/docs/man/FS/port.html, + httemplate/docs/man/FS/prepay_credit.html, + httemplate/docs/man/FS/session.html, + httemplate/docs/man/FS/svc_Common.html, + httemplate/docs/man/FS/svc_acct.html, + httemplate/docs/man/FS/svc_acct_pop.html, + httemplate/docs/man/FS/svc_acct_sm.html, + httemplate/docs/man/FS/svc_domain.html, + httemplate/docs/man/FS/svc_www.html, + httemplate/docs/man/FS/type_pkgs.html, httemplate/edit/part_bill_event.cgi, httemplate/edit/part_pkg.cgi, httemplate/edit/process/part_bill_event.cgi: - web interface for @@ -30234,7 +30388,45 @@ httemplate/docs/upgrade3.html, httemplate/docs/upgrade4.html, httemplate/docs/upgrade5.html, httemplate/docs/upgrade6.html, httemplate/docs/upgrade7.html, httemplate/docs/upgrade8.html, - bin/fs-setup, bin/masonize, bin/pod2x, httemplate/edit/agent.cgi, + httemplate/docs/man/FS.html, httemplate/docs/man/FS/Bill.html, + httemplate/docs/man/FS/CGI.html, + httemplate/docs/man/FS/CGIwrapper.html, + httemplate/docs/man/FS/Conf.html, + httemplate/docs/man/FS/Invoice.html, + httemplate/docs/man/FS/Record.html, + httemplate/docs/man/FS/SessionClient.html, + httemplate/docs/man/FS/SignupClient.html, + httemplate/docs/man/FS/UID.html, + httemplate/docs/man/FS/agent.html, + httemplate/docs/man/FS/agent_type.html, + httemplate/docs/man/FS/cust_bill.html, + httemplate/docs/man/FS/cust_bill_pkg.html, + httemplate/docs/man/FS/cust_credit.html, + httemplate/docs/man/FS/cust_main.html, + httemplate/docs/man/FS/cust_main_county.html, + httemplate/docs/man/FS/cust_main_invoice.html, + httemplate/docs/man/FS/cust_pay.html, + httemplate/docs/man/FS/cust_pay_batch.html, + httemplate/docs/man/FS/cust_pkg.html, + httemplate/docs/man/FS/cust_refund.html, + httemplate/docs/man/FS/cust_svc.html, + httemplate/docs/man/FS/domain_record.html, + httemplate/docs/man/FS/nas.html, + httemplate/docs/man/FS/part_pkg.html, + httemplate/docs/man/FS/part_referral.html, + httemplate/docs/man/FS/part_svc.html, + httemplate/docs/man/FS/pkg_svc.html, + httemplate/docs/man/FS/port.html, + httemplate/docs/man/FS/prepay_credit.html, + httemplate/docs/man/FS/session.html, + httemplate/docs/man/FS/svc_Common.html, + httemplate/docs/man/FS/svc_acct.html, + httemplate/docs/man/FS/svc_acct_pop.html, + httemplate/docs/man/FS/svc_acct_sm.html, + httemplate/docs/man/FS/svc_domain.html, + httemplate/docs/man/FS/svc_www.html, + httemplate/docs/man/FS/type_pkgs.html, bin/fs-setup, + bin/masonize, bin/pod2x, httemplate/edit/agent.cgi, httemplate/edit/agent_type.cgi, httemplate/edit/cust_credit.cgi, httemplate/edit/cust_main.cgi, httemplate/edit/cust_main_county-expand.cgi, diff --git a/debian/changelog b/debian/changelog index d53e90e84..23ca4d83e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +freeside (1.9.1-1) unstable; urgency=low + + * New upstream release + + -- Ivan Kohler Sat, 10 Oct 2009 18:57:01 -0700 + freeside (1.9.0~cvs0-1) unstable; urgency=low * Initial release diff --git a/rpm/freeside.spec b/rpm/freeside.spec index 7bf8abf86..931227043 100644 --- a/rpm/freeside.spec +++ b/rpm/freeside.spec @@ -1,5 +1,5 @@ %{!?_initrddir:%define _initrddir /etc/rc.d/init.d} -%{!?version:%define version 1.9} +%{!?version:%define version 1.9.1} %{!?release:%define release 8} Summary: Freeside ISP Billing System -- cgit v1.2.1 From 0b69c091543b56a45f2ae6b8718fc67f381a6686 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 11 Oct 2009 02:42:16 +0000 Subject: Updated for 1.9.1 --- ChangeLog | 7812 +++++++++++++++++++++++++++++++++++++++++++++++++++--- debian/changelog | 6 + 2 files changed, 7502 insertions(+), 316 deletions(-) diff --git a/ChangeLog b/ChangeLog index 48270b5ab..e844a1194 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-10-10 18:57 ivan + + * ChangeLog, rpm/freeside.spec, debian/changelog: Updated for 1.9.1 + 2009-10-10 18:50 ivan * Makefile, bin/cvs2cl: helps to have the tool @@ -2749,7 +2753,7 @@ report_receivables.html: add customer status to receivables report selection, hopefully help enet, RT#5187 -2009-04-15 20:58 rsiddall +2009-04-15 20:57 rsiddall * rpm/freeside.spec: More fixes for SuSE self-service: 1/ Put binaries in the right folder 2/ Make sure freeside group is @@ -3948,7 +3952,7 @@ * FS/FS/cust_pkg.pm: fix unsuspend-always_adjust_next_bill_date config, RT#4271 -2009-01-28 08:29 rsiddall +2009-01-28 08:28 rsiddall * rpm/freeside.spec: Removed conflict between core billing package and self-service RPMs so you can install them all on the same @@ -4121,7 +4125,7 @@ httemplate/view/cust_main/packages/location.html: finish package location tax reporing, RT#4499 -2009-01-18 13:06 rsiddall +2009-01-18 13:05 rsiddall * rpm/freeside.sysconfig: bash didn't like spaces on each side of an equals sign. @@ -5711,7 +5715,7 @@ * FS/FS/Tron.pm, httemplate/elements/mcp_lint.html: add unchecked vs. ok distinction to lint -2008-08-26 07:00 rsiddall +2008-08-26 06:59 rsiddall * rpm/freeside.spec: More changes to the self-service RPMs, mostly fixing up paths so the RPM-installed self-service files are not @@ -7105,8 +7109,8 @@ 2008-05-05 18:14 ivan * httemplate/: misc/batch-cust_pay.html, - elements/customer-table.html: agent-virtualize quick payment - entry + elements/customer-table.html, misc/elements/customer-table.html: + agent-virtualize quick payment entry 2008-05-04 19:11 ivan @@ -7574,6 +7578,17 @@ * httemplate/docs/: credits.html, license.html: adding license and credits in app itself +2008-04-01 16:26 ivan + + * fs_sesmon/: fs_session_server, FS-SessionClient/Changes, + FS-SessionClient/MANIFEST, FS-SessionClient/MANIFEST.SKIP, + FS-SessionClient/Makefile.PL, FS-SessionClient/SessionClient.pm, + FS-SessionClient/fs_sessiond, FS-SessionClient/test.pl, + FS-SessionClient/bin/freeside-login, + FS-SessionClient/bin/freeside-logout, + FS-SessionClient/cgi/login.cgi, FS-SessionClient/cgi/logout.cgi: + remove fs_sesmon + 2008-04-01 16:24 ivan * TODO: remove TODO @@ -7582,6 +7597,13 @@ * SCHEMA_CHANGE: remove SCHEMA_CHANGE +2008-04-01 16:23 ivan + + * fs_selfadmin/: README, fs_mailadmin_server, + FS-MailAdminServer/MailAdminClient.pm, + FS-MailAdminServer/fs_mailadmind, + FS-MailAdminServer/cgi/mailadmin.cgi: remove fs_selfadmin + 2008-04-01 16:20 ivan * README: welcome to the new world @@ -9135,6 +9157,704 @@ * httemplate/search/elements/search.html: i hope this allows IE to download excel over https? +2007-12-04 13:28 ivan + + * sql-ledger/: VERSION, am.pl, favicon.ico, index.html, login.pl, + menu.ini, setup.pl, sql-ledger.conf.default, sql-ledger.gif, + sql-ledger.png, SL/AM.pm, SL/AP.pm, SL/AR.pm, SL/BP.pm, SL/CA.pm, + SL/CP.pm, SL/CT.pm, SL/Form.pm, SL/GL.pm, SL/HR.pm, SL/IC.pm, + SL/IR.pm, SL/IS.pm, SL/Inifile.pm, SL/Mailer.pm, SL/Menu.pm, + SL/Num2text.pm, SL/OE.pm, SL/OP.pm, SL/PE.pm, SL/RC.pm, SL/RP.pm, + SL/User.pm, bin/js/menu.pl, bin/lynx/menu.pl, + bin/mozilla/admin.pl, bin/mozilla/am.pl, bin/mozilla/ap.pl, + bin/mozilla/ar.pl, bin/mozilla/arap.pl, bin/mozilla/arapprn.pl, + bin/mozilla/bp.pl, bin/mozilla/ca.pl, bin/mozilla/cp.pl, + bin/mozilla/ct.pl, bin/mozilla/gl.pl, bin/mozilla/hr.pl, + bin/mozilla/ic.pl, bin/mozilla/io.pl, bin/mozilla/ir.pl, + bin/mozilla/is.pl, bin/mozilla/login.pl, bin/mozilla/menu.pl, + bin/mozilla/oe.pl, bin/mozilla/pe.pl, bin/mozilla/pos.pl, + bin/mozilla/ps.pl, bin/mozilla/pw.pl, bin/mozilla/rc.pl, + bin/mozilla/rp.pl, css/sql-ledger.css, doc/COPYING, + doc/COPYRIGHT, doc/README, doc/README.DB2, doc/UPGRADE-1.6-1.8, + doc/UPGRADE-1.8-1.8.3, doc/UPGRADE-1.8.3-1.8.4, + doc/UPGRADE-1.8.4-1.8.5, doc/UPGRADE-1.8.5-1.8.7, + doc/UPGRADE-1.8.7-2.0.0, doc/UPGRADE-2.0-2.0.8, + doc/UPGRADE-2.0.8-2.0.9, doc/UPGRADE-2.0.9-2.2.0, + doc/UPGRADE-2.2.0-2.2.7, doc/UPGRADE-2.2.7-2.4.0, + doc/UPGRADE-2.4.0-2.4.1, doc/UPGRADE-2.4.1-2.4.2, + doc/UPGRADE-2.4.2-2.4.3, doc/UPGRADE-2.4.3-2.4.4, doc/faq.html, + locale/be_nl/COPYING, locale/be_nl/LANGUAGE, + locale/be_nl/Num2text, locale/be_nl/admin, locale/be_nl/all, + locale/be_nl/am, locale/be_nl/ap, locale/be_nl/ar, + locale/be_nl/arap, locale/be_nl/arapprn, locale/be_nl/bp, + locale/be_nl/ca, locale/be_nl/cp, locale/be_nl/ct, + locale/be_nl/gl, locale/be_nl/hr, locale/be_nl/ic, + locale/be_nl/io, locale/be_nl/ir, locale/be_nl/is, + locale/be_nl/login, locale/be_nl/menu, locale/be_nl/oe, + locale/be_nl/pe, locale/be_nl/pos, locale/be_nl/ps, + locale/be_nl/pw, locale/be_nl/rc, locale/be_nl/rp, + locale/br/COPYING, locale/br/LANGUAGE, locale/br/admin, + locale/br/all, locale/br/am, locale/br/ap, locale/br/ar, + locale/br/arap, locale/br/arapprn, locale/br/bp, locale/br/ca, + locale/br/cp, locale/br/ct, locale/br/gl, locale/br/hr, + locale/br/ic, locale/br/io, locale/br/ir, locale/br/is, + locale/br/login, locale/br/menu, locale/br/oe, locale/br/pe, + locale/br/pos, locale/br/ps, locale/br/pw, locale/br/rc, + locale/br/rp, locale/cn_utf/COPYING, locale/cn_utf/LANGUAGE, + locale/cn_utf/admin, locale/cn_utf/all, locale/cn_utf/am, + locale/cn_utf/ap, locale/cn_utf/ar, locale/cn_utf/arap, + locale/cn_utf/arapprn, locale/cn_utf/bp, locale/cn_utf/ca, + locale/cn_utf/cp, locale/cn_utf/ct, locale/cn_utf/gl, + locale/cn_utf/hr, locale/cn_utf/ic, locale/cn_utf/io, + locale/cn_utf/ir, locale/cn_utf/is, locale/cn_utf/login, + locale/cn_utf/menu, locale/cn_utf/oe, locale/cn_utf/pe, + locale/cn_utf/pos, locale/cn_utf/ps, locale/cn_utf/pw, + locale/cn_utf/rc, locale/cn_utf/rp, locale/co/COPYING, + locale/co/LANGUAGE, locale/co/Num2text, locale/co/admin, + locale/co/all, locale/co/am, locale/co/ap, locale/co/ar, + locale/co/arap, locale/co/arapprn, locale/co/bp, locale/co/ca, + locale/co/cp, locale/co/ct, locale/co/gl, locale/co/hr, + locale/co/ic, locale/co/io, locale/co/ir, locale/co/is, + locale/co/login, locale/co/menu, locale/co/oe, locale/co/pe, + locale/co/pos, locale/co/ps, locale/co/pw, locale/co/rc, + locale/co/rp, locale/ct/COPYING, locale/ct/LANGUAGE, + locale/ct/admin, locale/ct/all, locale/ct/am, locale/ct/ap, + locale/ct/ar, locale/ct/arap, locale/ct/arapprn, locale/ct/bp, + locale/ct/ca, locale/ct/cp, locale/ct/ct, locale/ct/gl, + locale/ct/hr, locale/ct/ic, locale/ct/io, locale/ct/ir, + locale/ct/is, locale/ct/login, locale/ct/menu, locale/ct/oe, + locale/ct/pe, locale/ct/pos, locale/ct/ps, locale/ct/pw, + locale/ct/rc, locale/ct/rp, locale/cz/COPYING, + locale/cz/LANGUAGE, locale/cz/admin, locale/cz/all, locale/cz/am, + locale/cz/ap, locale/cz/ar, locale/cz/arap, locale/cz/arapprn, + locale/cz/bp, locale/cz/ca, locale/cz/cp, locale/cz/ct, + locale/cz/gl, locale/cz/hr, locale/cz/ic, locale/cz/io, + locale/cz/ir, locale/cz/is, locale/cz/login, locale/cz/menu, + locale/cz/oe, locale/cz/pe, locale/cz/pos, locale/cz/ps, + locale/cz/pw, locale/cz/rc, locale/cz/rp, locale/de/COPYING, + locale/de/LANGUAGE, locale/de/Num2text, locale/de/admin, + locale/de/am, locale/de/ap, locale/de/ar, locale/de/arap, + locale/de/arapprn, locale/de/bp, locale/de/ca, locale/de/cp, + locale/de/ct, locale/de/gl, locale/de/hr, locale/de/ic, + locale/de/io, locale/de/ir, locale/de/is, locale/de/locales.pl, + locale/de/login, locale/de/menu, locale/de/oe, locale/de/pe, + locale/de/pos, locale/de/ps, locale/de/pw, locale/de/rc, + locale/de/rp, locale/dk/COPYING, locale/dk/LANGUAGE, + locale/dk/admin, locale/dk/all, locale/dk/am, locale/dk/ap, + locale/dk/ar, locale/dk/arap, locale/dk/arapprn, locale/dk/bp, + locale/dk/ca, locale/dk/cp, locale/dk/ct, locale/dk/gl, + locale/dk/hr, locale/dk/ic, locale/dk/io, locale/dk/ir, + locale/dk/is, locale/dk/login, locale/dk/menu, locale/dk/oe, + locale/dk/pe, locale/dk/pos, locale/dk/ps, locale/dk/pw, + locale/dk/rc, locale/dk/rp, locale/ec/COPYING, + locale/ec/LANGUAGE, locale/ec/Num2text, locale/ec/admin, + locale/ec/all, locale/ec/am, locale/ec/ap, locale/ec/ar, + locale/ec/arap, locale/ec/arapprn, locale/ec/bp, locale/ec/ca, + locale/ec/cp, locale/ec/ct, locale/ec/gl, locale/ec/hr, + locale/ec/ic, locale/ec/io, locale/ec/ir, locale/ec/is, + locale/ec/login, locale/ec/menu, locale/ec/oe, locale/ec/pe, + locale/ec/pos, locale/ec/ps, locale/ec/pw, locale/ec/rc, + locale/ec/rp, locale/ee/COPYING, locale/ee/LANGUAGE, + locale/ee/Num2text, locale/ee/admin, locale/ee/all, locale/ee/am, + locale/ee/ap, locale/ee/ar, locale/ee/arap, locale/ee/arapprn, + locale/ee/bp, locale/ee/ca, locale/ee/cp, locale/ee/ct, + locale/ee/gl, locale/ee/hr, locale/ee/ic, locale/ee/io, + locale/ee/ir, locale/ee/is, locale/ee/login, locale/ee/menu, + locale/ee/oe, locale/ee/pe, locale/ee/pos, locale/ee/ps, + locale/ee/pw, locale/ee/rc, locale/ee/rp, locale/eg/COPYING, + locale/eg/LANGUAGE, locale/eg/admin, locale/eg/all, locale/eg/am, + locale/eg/ap, locale/eg/ar, locale/eg/arap, locale/eg/arapprn, + locale/eg/bp, locale/eg/ca, locale/eg/cp, locale/eg/ct, + locale/eg/gl, locale/eg/hr, locale/eg/ic, locale/eg/io, + locale/eg/ir, locale/eg/is, locale/eg/login, locale/eg/menu, + locale/eg/oe, locale/eg/pe, locale/eg/pos, locale/eg/ps, + locale/eg/pw, locale/eg/rc, locale/eg/rp, locale/en_GB/COPYING, + locale/en_GB/LANGUAGE, locale/en_GB/admin, locale/en_GB/all, + locale/en_GB/am, locale/en_GB/ap, locale/en_GB/ar, + locale/en_GB/arap, locale/en_GB/arapprn, locale/en_GB/bp, + locale/en_GB/ca, locale/en_GB/cp, locale/en_GB/ct, + locale/en_GB/gl, locale/en_GB/hr, locale/en_GB/ic, + locale/en_GB/io, locale/en_GB/ir, locale/en_GB/is, + locale/en_GB/login, locale/en_GB/menu, locale/en_GB/oe, + locale/en_GB/pe, locale/en_GB/pos, locale/en_GB/ps, + locale/en_GB/pw, locale/en_GB/rc, locale/en_GB/rp, + locale/es_iso/COPYING, locale/es_iso/LANGUAGE, + locale/es_iso/Num2text, locale/es_iso/admin, locale/es_iso/all, + locale/es_iso/am, locale/es_iso/ap, locale/es_iso/ar, + locale/es_iso/arap, locale/es_iso/arapprn, locale/es_iso/bp, + locale/es_iso/ca, locale/es_iso/cp, locale/es_iso/ct, + locale/es_iso/gl, locale/es_iso/hr, locale/es_iso/ic, + locale/es_iso/io, locale/es_iso/ir, locale/es_iso/is, + locale/es_iso/login, locale/es_iso/menu, locale/es_iso/oe, + locale/es_iso/pe, locale/es_iso/pos, locale/es_iso/ps, + locale/es_iso/pw, locale/es_iso/rc, locale/es_iso/rp, + locale/es_utf/COPYING, locale/es_utf/LANGUAGE, + locale/es_utf/Num2text, locale/es_utf/admin, locale/es_utf/all, + locale/es_utf/am, locale/es_utf/ap, locale/es_utf/ar, + locale/es_utf/arap, locale/es_utf/arapprn, locale/es_utf/bp, + locale/es_utf/ca, locale/es_utf/cp, locale/es_utf/ct, + locale/es_utf/gl, locale/es_utf/hr, locale/es_utf/ic, + locale/es_utf/io, locale/es_utf/ir, locale/es_utf/is, + locale/es_utf/login, locale/es_utf/menu, locale/es_utf/oe, + locale/es_utf/pe, locale/es_utf/pos, locale/es_utf/ps, + locale/es_utf/pw, locale/es_utf/rc, locale/es_utf/rp, + locale/fi/COPYING, locale/fi/LANGUAGE, locale/fi/admin, + locale/fi/all, locale/fi/am, locale/fi/ap, locale/fi/ar, + locale/fi/arap, locale/fi/arapprn, locale/fi/bp, locale/fi/ca, + locale/fi/cp, locale/fi/ct, locale/fi/gl, locale/fi/hr, + locale/fi/ic, locale/fi/io, locale/fi/ir, locale/fi/is, + locale/fi/login, locale/fi/menu, locale/fi/oe, locale/fi/pe, + locale/fi/pos, locale/fi/ps, locale/fi/pw, locale/fi/rc, + locale/fi/rp, locale/fr/COPYING, locale/fr/LANGUAGE, + locale/fr/Num2text, locale/fr/admin, locale/fr/all, locale/fr/am, + locale/fr/ap, locale/fr/ar, locale/fr/arap, locale/fr/arapprn, + locale/fr/bp, locale/fr/ca, locale/fr/cp, locale/fr/ct, + locale/fr/gl, locale/fr/hr, locale/fr/ic, locale/fr/io, + locale/fr/ir, locale/fr/is, locale/fr/login, locale/fr/menu, + locale/fr/oe, locale/fr/pe, locale/fr/pos, locale/fr/ps, + locale/fr/pw, locale/fr/rc, locale/fr/rp, locale/gr/COPYING, + locale/gr/LANGUAGE, locale/gr/admin, locale/gr/all, locale/gr/am, + locale/gr/ap, locale/gr/ar, locale/gr/arap, locale/gr/arapprn, + locale/gr/bp, locale/gr/ca, locale/gr/cp, locale/gr/ct, + locale/gr/gl, locale/gr/hr, locale/gr/ic, locale/gr/io, + locale/gr/ir, locale/gr/is, locale/gr/login, locale/gr/menu, + locale/gr/oe, locale/gr/pe, locale/gr/pos, locale/gr/ps, + locale/gr/pw, locale/gr/rc, locale/gr/rp, locale/hu/COPYING, + locale/hu/LANGUAGE, locale/hu/Num2text, locale/hu/admin, + locale/hu/all, locale/hu/am, locale/hu/ap, locale/hu/ar, + locale/hu/arap, locale/hu/arapprn, locale/hu/bp, locale/hu/ca, + locale/hu/cp, locale/hu/ct, locale/hu/gl, locale/hu/hr, + locale/hu/ic, locale/hu/io, locale/hu/ir, locale/hu/is, + locale/hu/login, locale/hu/menu, locale/hu/oe, locale/hu/pe, + locale/hu/pos, locale/hu/ps, locale/hu/pw, locale/hu/rc, + locale/hu/rp, locale/is/COPYING, locale/is/LANGUAGE, + locale/is/admin, locale/is/all, locale/is/am, locale/is/ap, + locale/is/ar, locale/is/arap, locale/is/arapprn, locale/is/bp, + locale/is/ca, locale/is/cp, locale/is/ct, locale/is/gl, + locale/is/hr, locale/is/ic, locale/is/io, locale/is/ir, + locale/is/is, locale/is/login, locale/is/menu, locale/is/oe, + locale/is/pe, locale/is/pos, locale/is/ps, locale/is/pw, + locale/is/rc, locale/is/rp, locale/it/COPYING, + locale/it/LANGUAGE, locale/it/Num2text, locale/it/admin, + locale/it/all, locale/it/am, locale/it/ap, locale/it/ar, + locale/it/arap, locale/it/arapprn, locale/it/bp, locale/it/ca, + locale/it/cp, locale/it/ct, locale/it/gl, locale/it/hr, + locale/it/ic, locale/it/io, locale/it/ir, locale/it/is, + locale/it/login, locale/it/menu, locale/it/oe, locale/it/pe, + locale/it/pos, locale/it/ps, locale/it/pw, locale/it/qe, + locale/it/rc, locale/it/rp, locale/lt/COPYING, + locale/lt/LANGUAGE, locale/lt/admin, locale/lt/all, locale/lt/am, + locale/lt/ap, locale/lt/ar, locale/lt/arap, locale/lt/arapprn, + locale/lt/bp, locale/lt/ca, locale/lt/cp, locale/lt/ct, + locale/lt/gl, locale/lt/hr, locale/lt/ic, locale/lt/io, + locale/lt/ir, locale/lt/is, locale/lt/login, locale/lt/menu, + locale/lt/oe, locale/lt/pe, locale/lt/pos, locale/lt/ps, + locale/lt/pw, locale/lt/rc, locale/lt/rp, locale/lv/COPYING, + locale/lv/LANGUAGE, locale/lv/admin, locale/lv/all, locale/lv/am, + locale/lv/ap, locale/lv/ar, locale/lv/arap, locale/lv/arapprn, + locale/lv/bp, locale/lv/ca, locale/lv/cp, locale/lv/ct, + locale/lv/gl, locale/lv/hr, locale/lv/ic, locale/lv/io, + locale/lv/ir, locale/lv/is, locale/lv/login, locale/lv/menu, + locale/lv/oe, locale/lv/pe, locale/lv/pos, locale/lv/ps, + locale/lv/pw, locale/lv/rc, locale/lv/rp, locale/mx/COPYING, + locale/mx/LANGUAGE, locale/mx/admin, locale/mx/all, locale/mx/am, + locale/mx/ap, locale/mx/ar, locale/mx/arap, locale/mx/arapprn, + locale/mx/bp, locale/mx/ca, locale/mx/cp, locale/mx/ct, + locale/mx/gl, locale/mx/hr, locale/mx/ic, locale/mx/io, + locale/mx/ir, locale/mx/is, locale/mx/login, locale/mx/menu, + locale/mx/oe, locale/mx/pe, locale/mx/pos, locale/mx/ps, + locale/mx/pw, locale/mx/rc, locale/mx/rp, locale/nb/COPYING, + locale/nb/LANGUAGE, locale/nb/admin, locale/nb/all, locale/nb/am, + locale/nb/ap, locale/nb/ar, locale/nb/arap, locale/nb/arapprn, + locale/nb/bp, locale/nb/ca, locale/nb/cp, locale/nb/ct, + locale/nb/gl, locale/nb/hr, locale/nb/ic, locale/nb/io, + locale/nb/ir, locale/nb/is, locale/nb/login, locale/nb/menu, + locale/nb/oe, locale/nb/pe, locale/nb/pos, locale/nb/ps, + locale/nb/pw, locale/nb/rc, locale/nb/rp, locale/nl/COPYING, + locale/nl/LANGUAGE, locale/nl/Num2text, locale/nl/admin, + locale/nl/all, locale/nl/am, locale/nl/ap, locale/nl/ar, + locale/nl/arap, locale/nl/arapprn, locale/nl/bp, locale/nl/ca, + locale/nl/cp, locale/nl/ct, locale/nl/gl, locale/nl/hr, + locale/nl/ic, locale/nl/io, locale/nl/ir, locale/nl/is, + locale/nl/login, locale/nl/menu, locale/nl/oe, locale/nl/pe, + locale/nl/pos, locale/nl/ps, locale/nl/pw, locale/nl/rc, + locale/nl/rp, locale/pa/COPYING, locale/pa/LANGUAGE, + locale/pa/admin, locale/pa/all, locale/pa/am, locale/pa/ap, + locale/pa/ar, locale/pa/arap, locale/pa/arapprn, locale/pa/bp, + locale/pa/ca, locale/pa/cp, locale/pa/ct, locale/pa/gl, + locale/pa/hr, locale/pa/ic, locale/pa/io, locale/pa/ir, + locale/pa/is, locale/pa/login, locale/pa/menu, locale/pa/oe, + locale/pa/pe, locale/pa/pos, locale/pa/ps, locale/pa/pw, + locale/pa/rc, locale/pa/rp, locale/pl/COPYING, + locale/pl/LANGUAGE, locale/pl/admin, locale/pl/all, locale/pl/am, + locale/pl/ap, locale/pl/ar, locale/pl/arap, locale/pl/arapprn, + locale/pl/bp, locale/pl/ca, locale/pl/cp, locale/pl/ct, + locale/pl/gl, locale/pl/hr, locale/pl/ic, locale/pl/io, + locale/pl/ir, locale/pl/is, locale/pl/login, locale/pl/menu, + locale/pl/oe, locale/pl/pe, locale/pl/pos, locale/pl/ps, + locale/pl/pw, locale/pl/rc, locale/pl/rp, locale/pt/COPYING, + locale/pt/LANGUAGE, locale/pt/admin, locale/pt/all, locale/pt/am, + locale/pt/ap, locale/pt/ar, locale/pt/arap, locale/pt/arapprn, + locale/pt/bp, locale/pt/ca, locale/pt/cp, locale/pt/ct, + locale/pt/gl, locale/pt/hr, locale/pt/ic, locale/pt/io, + locale/pt/ir, locale/pt/is, locale/pt/login, locale/pt/menu, + locale/pt/oe, locale/pt/pe, locale/pt/pos, locale/pt/ps, + locale/pt/pw, locale/pt/rc, locale/pt/rp, locale/ru/COPYING, + locale/ru/LANGUAGE, locale/ru/admin, locale/ru/all, locale/ru/am, + locale/ru/ap, locale/ru/ar, locale/ru/arap, locale/ru/arapprn, + locale/ru/bp, locale/ru/ca, locale/ru/cp, locale/ru/ct, + locale/ru/gl, locale/ru/hr, locale/ru/ic, locale/ru/io, + locale/ru/ir, locale/ru/is, locale/ru/login, locale/ru/menu, + locale/ru/oe, locale/ru/pe, locale/ru/pos, locale/ru/ps, + locale/ru/pw, locale/ru/rc, locale/ru/rp, locale/se/COPYING, + locale/se/LANGUAGE, locale/se/admin, locale/se/all, locale/se/am, + locale/se/ap, locale/se/ar, locale/se/arap, locale/se/arapprn, + locale/se/bp, locale/se/ca, locale/se/cp, locale/se/ct, + locale/se/gl, locale/se/hr, locale/se/ic, locale/se/io, + locale/se/ir, locale/se/is, locale/se/login, locale/se/menu, + locale/se/oe, locale/se/pe, locale/se/pos, locale/se/ps, + locale/se/pw, locale/se/rc, locale/se/rp, locale/sv/COPYING, + locale/sv/LANGUAGE, locale/sv/admin, locale/sv/all, locale/sv/am, + locale/sv/ap, locale/sv/ar, locale/sv/arap, locale/sv/arapprn, + locale/sv/bp, locale/sv/ca, locale/sv/cp, locale/sv/ct, + locale/sv/gl, locale/sv/hr, locale/sv/ic, locale/sv/io, + locale/sv/ir, locale/sv/is, locale/sv/login, locale/sv/menu, + locale/sv/oe, locale/sv/pe, locale/sv/pos, locale/sv/ps, + locale/sv/pw, locale/sv/rc, locale/sv/rp, locale/tr/COPYING, + locale/tr/LANGUAGE, locale/tr/admin, locale/tr/all, locale/tr/am, + locale/tr/ap, locale/tr/ar, locale/tr/arap, locale/tr/arapprn, + locale/tr/bp, locale/tr/ca, locale/tr/cp, locale/tr/ct, + locale/tr/gl, locale/tr/hr, locale/tr/ic, locale/tr/io, + locale/tr/ir, locale/tr/is, locale/tr/login, locale/tr/menu, + locale/tr/oe, locale/tr/pe, locale/tr/pos, locale/tr/ps, + locale/tr/pw, locale/tr/rc, locale/tr/rp, locale/tw_big5/COPYING, + locale/tw_big5/LANGUAGE, locale/tw_big5/admin, + locale/tw_big5/all, locale/tw_big5/am, locale/tw_big5/ap, + locale/tw_big5/ar, locale/tw_big5/arap, locale/tw_big5/arapprn, + locale/tw_big5/bp, locale/tw_big5/ca, locale/tw_big5/cp, + locale/tw_big5/ct, locale/tw_big5/gl, locale/tw_big5/hr, + locale/tw_big5/ic, locale/tw_big5/io, locale/tw_big5/ir, + locale/tw_big5/is, locale/tw_big5/login, locale/tw_big5/menu, + locale/tw_big5/oe, locale/tw_big5/pe, locale/tw_big5/pos, + locale/tw_big5/ps, locale/tw_big5/pw, locale/tw_big5/rc, + locale/tw_big5/rp, locale/tw_big5/temp, locale/tw_utf/COPYING, + locale/tw_utf/LANGUAGE, locale/tw_utf/admin, locale/tw_utf/all, + locale/tw_utf/am, locale/tw_utf/ap, locale/tw_utf/ar, + locale/tw_utf/arap, locale/tw_utf/arapprn, locale/tw_utf/bp, + locale/tw_utf/ca, locale/tw_utf/cp, locale/tw_utf/ct, + locale/tw_utf/gl, locale/tw_utf/hr, locale/tw_utf/ic, + locale/tw_utf/io, locale/tw_utf/ir, locale/tw_utf/is, + locale/tw_utf/login, locale/tw_utf/menu, locale/tw_utf/oe, + locale/tw_utf/pe, locale/tw_utf/pos, locale/tw_utf/ps, + locale/tw_utf/pw, locale/tw_utf/rc, locale/tw_utf/rp, + locale/ua/COPYING, locale/ua/LANGUAGE, locale/ua/admin, + locale/ua/all, locale/ua/am, locale/ua/ap, locale/ua/ar, + locale/ua/arap, locale/ua/arapprn, locale/ua/bp, locale/ua/ca, + locale/ua/cp, locale/ua/ct, locale/ua/gl, locale/ua/hr, + locale/ua/ic, locale/ua/io, locale/ua/ir, locale/ua/is, + locale/ua/login, locale/ua/menu, locale/ua/oe, locale/ua/pe, + locale/ua/pos, locale/ua/ps, locale/ua/pw, locale/ua/rc, + locale/ua/rp, locale/ve/COPYING, locale/ve/LANGUAGE, + locale/ve/admin, locale/ve/all, locale/ve/am, locale/ve/ap, + locale/ve/ar, locale/ve/arap, locale/ve/arapprn, locale/ve/bp, + locale/ve/ca, locale/ve/cp, locale/ve/ct, locale/ve/gl, + locale/ve/hr, locale/ve/ic, locale/ve/io, locale/ve/ir, + locale/ve/is, locale/ve/login, locale/ve/menu, locale/ve/oe, + locale/ve/pe, locale/ve/pos, locale/ve/ps, locale/ve/pw, + locale/ve/rc, locale/ve/rp, sql/Austria-chart.sql, + sql/Austria-gifi.sql, sql/Belgium-chart.sql, + sql/Belgium-gifi.sql, sql/Brazil_General-chart.sql, + sql/Canada-English-gifi.sql, + sql/Canada-English_General-chart.sql, sql/Canada-French-gifi.sql, + sql/Colombia-PUC-chart.sql, sql/Colombia-PUC-gifi.sql, + sql/Czech-Republic-chart.sql, sql/DB2-create.sql, + sql/DB2-indices.sql, sql/DB2-remove.sql, sql/DB2-set.sql, + sql/DB2-sql-ledger.order, sql/DB2-tables.sql, + sql/Danish_Default-chart.sql, sql/Default-chart.sql, + sql/Dutch_Default-chart.sql, sql/Dutch_Standard-chart.sql, + sql/Egypt-chart.sql, sql/France-chart.sql, + sql/German-Sample-chart.sql, sql/German-Sample-gifi.sql, + sql/Germany-DATEV-SKR03-chart.sql, + sql/Germany-DATEV-SKR03-gifi.sql, sql/Germany-SKR03-chart.sql, + sql/Germany-SKR03-gifi.sql, sql/Hungary-chart.sql, + sql/Hungary-gifi.sql, sql/Italy-gifi.sql, + sql/Italy_General-chart.sql, sql/Italy_cc2424-chart.sql, + sql/Latvia-chart.sql, sql/NAICS.sql, + sql/Norwegian_Default-chart.sql, sql/Oracle-indices.sql, + sql/Oracle-tables.sql, sql/Oracle-upgrade-1.8.0-1.8.4.sql, + sql/Oracle-upgrade-1.8.4-1.8.5.sql, + sql/Oracle-upgrade-1.8.5-2.0.0.sql, + sql/Oracle-upgrade-2.0.0-2.0.8.sql, + sql/Oracle-upgrade-2.0.8-2.2.0.sql, sql/Pg-functions.sql, + sql/Pg-indices.sql, sql/Pg-tables.sql, + sql/Pg-upgrade-1.2.6-1.2.7.sql, sql/Pg-upgrade-1.2.7-1.4.0.sql, + sql/Pg-upgrade-1.4.0-1.6.0.sql, sql/Pg-upgrade-1.6.0-1.8.0.sql, + sql/Pg-upgrade-1.8.0-1.8.4.sql, sql/Pg-upgrade-1.8.4-1.8.5.sql, + sql/Pg-upgrade-1.8.5-2.0.0.sql, sql/Pg-upgrade-2.0.0-2.0.8.sql, + sql/Pg-upgrade-2.0.8-2.2.0.sql, sql/Pg-upgrade-2.2.0-2.3.0.sql, + sql/Pg-upgrade-2.3.0-2.3.1.sql, sql/Pg-upgrade-2.3.1-2.3.3.sql, + sql/Pg-upgrade-2.3.3-2.3.4.sql, sql/Pg-upgrade-2.3.4-2.3.5.sql, + sql/Pg-upgrade-2.3.5-2.3.6.sql, sql/Pg-upgrade-2.3.6-2.3.7.sql, + sql/Pg-upgrade-2.3.7-2.3.8.sql, sql/Pg-upgrade-2.3.8-2.3.9.sql, + sql/Pg-upgrade-2.3.9-2.4.2.sql, sql/Pg-upgrade-2.4.2-2.4.3.sql, + sql/Pg-upgrade-2.4.3-2.4.4.sql, sql/Poland-chart.sql, + sql/Simplified-Chinese_Default-UTF8-chart.sql, + sql/Simplified-Chinese_Default-chart.sql, + sql/Spain-ISO-chart.sql, sql/Spain-UTF8-chart.sql, + sql/Swedish-chart.sql, sql/Swiss-German-chart.sql, + sql/Swiss-German-gifi.sql, + sql/Traditional-Chinese_Default-UTF8-chart.sql, + sql/Traditional-Chinese_Default-chart.sql, + sql/US_General-chart.sql, sql/US_Manufacturing-chart.sql, + sql/US_Service_Company-chart.sql, + templates/Brazilian_Portuguese-ap_transaction.html, + templates/Brazilian_Portuguese-ap_transaction.tex, + templates/Brazilian_Portuguese-ar_transaction.html, + templates/Brazilian_Portuguese-ar_transaction.tex, + templates/Brazilian_Portuguese-balance_sheet.html, + templates/Brazilian_Portuguese-bin_list.html, + templates/Brazilian_Portuguese-bin_list.tex, + templates/Brazilian_Portuguese-check.tex, + templates/Brazilian_Portuguese-income_statement.html, + templates/Brazilian_Portuguese-invoice.html, + templates/Brazilian_Portuguese-invoice.tex, + templates/Brazilian_Portuguese-packing_list.html, + templates/Brazilian_Portuguese-packing_list.tex, + templates/Brazilian_Portuguese-pick_list.html, + templates/Brazilian_Portuguese-pick_list.tex, + templates/Brazilian_Portuguese-pos_invoice.txt, + templates/Brazilian_Portuguese-purchase_order.html, + templates/Brazilian_Portuguese-purchase_order.tex, + templates/Brazilian_Portuguese-receipt.tex, + templates/Brazilian_Portuguese-request_quotation.html, + templates/Brazilian_Portuguese-request_quotation.tex, + templates/Brazilian_Portuguese-sales_order.html, + templates/Brazilian_Portuguese-sales_order.tex, + templates/Brazilian_Portuguese-sales_quotation.html, + templates/Brazilian_Portuguese-sales_quotation.tex, + templates/Brazilian_Portuguese-statement.html, + templates/Brazilian_Portuguese-statement.tex, + templates/Brazilian_Portuguese-work_order.html, + templates/Brazilian_Portuguese-work_order.tex, + templates/Danish-ap_transaction.html, + templates/Danish-ap_transaction.tex, + templates/Danish-ar_transaction.html, + templates/Danish-ar_transaction.tex, + templates/Danish-balance_sheet.html, + templates/Danish-bin_list.html, templates/Danish-bin_list.tex, + templates/Danish-check.tex, + templates/Danish-income_statement.html, + templates/Danish-invoice.html, templates/Danish-invoice.tex, + templates/Danish-packing_list.html, + templates/Danish-packing_list.tex, + templates/Danish-pick_list.html, templates/Danish-pick_list.tex, + templates/Danish-pos_invoice.txt, + templates/Danish-purchase_order.html, + templates/Danish-purchase_order.tex, + templates/Danish-receipt.tex, + templates/Danish-request_quotation.html, + templates/Danish-request_quotation.tex, + templates/Danish-sales_order.html, + templates/Danish-sales_order.tex, + templates/Danish-sales_quotation.html, + templates/Danish-sales_quotation.tex, + templates/Danish-statement.html, templates/Danish-statement.tex, + templates/Danish-work_order.html, + templates/Danish-work_order.tex, + templates/Default-ap_transaction.html, + templates/Default-ap_transaction.tex, + templates/Default-ar_transaction.html, + templates/Default-ar_transaction.tex, + templates/Default-balance_sheet.html, + templates/Default-bin_list.html, templates/Default-bin_list.tex, + templates/Default-check.tex, + templates/Default-income_statement.html, + templates/Default-invoice.html, templates/Default-invoice.tex, + templates/Default-packing_list.html, + templates/Default-packing_list.tex, + templates/Default-pick_list.html, + templates/Default-pick_list.tex, + templates/Default-pos_invoice.txt, + templates/Default-purchase_order.html, + templates/Default-purchase_order.tex, + templates/Default-receipt.tex, + templates/Default-request_quotation.html, + templates/Default-request_quotation.tex, + templates/Default-sales_order.html, + templates/Default-sales_order.tex, + templates/Default-sales_quotation.html, + templates/Default-sales_quotation.tex, + templates/Default-statement.html, + templates/Default-statement.tex, + templates/Default-work_order.html, + templates/Default-work_order.tex, + templates/Dutch-ap_transaction.html, + templates/Dutch-ap_transaction.tex, + templates/Dutch-ar_transaction.html, + templates/Dutch-ar_transaction.tex, + templates/Dutch-balance_sheet.html, + templates/Dutch-bin_list.html, templates/Dutch-bin_list.tex, + templates/Dutch-check.tex, templates/Dutch-income_statement.html, + templates/Dutch-invoice.html, templates/Dutch-invoice.tex, + templates/Dutch-packing_list.html, + templates/Dutch-packing_list.tex, templates/Dutch-pick_list.html, + templates/Dutch-pick_list.tex, templates/Dutch-pos_invoice.txt, + templates/Dutch-purchase_order.html, + templates/Dutch-purchase_order.tex, templates/Dutch-receipt.tex, + templates/Dutch-request_quotation.html, + templates/Dutch-request_quotation.tex, + templates/Dutch-sales_order.html, + templates/Dutch-sales_order.tex, + templates/Dutch-sales_quotation.html, + templates/Dutch-sales_quotation.tex, + templates/Dutch-statement.html, templates/Dutch-statement.tex, + templates/Dutch-work_order.html, templates/Dutch-work_order.tex, + templates/Estonian-ap_transaction.html, + templates/Estonian-ap_transaction.tex, + templates/Estonian-ar_transaction.html, + templates/Estonian-ar_transaction.tex, + templates/Estonian-balance_sheet.html, + templates/Estonian-bin_list.html, + templates/Estonian-bin_list.tex, templates/Estonian-check.tex, + templates/Estonian-income_statement.html, + templates/Estonian-invoice.html, templates/Estonian-invoice.tex, + templates/Estonian-packing_list.html, + templates/Estonian-packing_list.tex, + templates/Estonian-pick_list.html, + templates/Estonian-pick_list.tex, + templates/Estonian-pos_invoice.txt, + templates/Estonian-purchase_order.html, + templates/Estonian-purchase_order.tex, + templates/Estonian-receipt.tex, + templates/Estonian-request_quotation.html, + templates/Estonian-request_quotation.tex, + templates/Estonian-sales_order.html, + templates/Estonian-sales_order.tex, + templates/Estonian-statement.html, + templates/Estonian-statement.tex, + templates/Estonian-work_order.html, + templates/Estonian-work_order.tex, + templates/French-ap_transaction.html, + templates/French-ap_transaction.tex, + templates/French-ar_transaction.html, + templates/French-ar_transaction.tex, + templates/French-balance_sheet.html, + templates/French-bin_list.html, templates/French-bin_list.tex, + templates/French-check.tex, + templates/French-income_statement.html, + templates/French-invoice.html, templates/French-invoice.tex, + templates/French-packing_list.html, + templates/French-packing_list.tex, + templates/French-pick_list.html, templates/French-pick_list.tex, + templates/French-pos_invoice.txt, + templates/French-purchase_order.html, + templates/French-purchase_order.tex, + templates/French-receipt.tex, + templates/French-request_quotation.html, + templates/French-request_quotation.tex, + templates/French-sales_order.html, + templates/French-sales_order.tex, + templates/French-sales_quotation.html, + templates/French-sales_quotation.tex, + templates/French-statement.html, templates/French-statement.tex, + templates/French-work_order.html, + templates/French-work_order.tex, + templates/German-ap_transaction.html, + templates/German-ap_transaction.tex, + templates/German-ar_transaction.html, + templates/German-ar_transaction.tex, + templates/German-balance_sheet.html, + templates/German-bin_list.html, templates/German-bin_list.tex, + templates/German-check.tex, + templates/German-income_statement.html, + templates/German-invoice.html, templates/German-invoice.tex, + templates/German-packing_list.html, + templates/German-packing_list.tex, + templates/German-pick_list.html, templates/German-pick_list.tex, + templates/German-pos_invoice.txt, + templates/German-purchase_order.html, + templates/German-purchase_order.tex, + templates/German-receipt.tex, + templates/German-request_quotation.html, + templates/German-request_quotation.tex, + templates/German-sales_order.html, + templates/German-sales_order.tex, + templates/German-sales_quotation.html, + templates/German-sales_quotation.tex, + templates/German-statement.html, templates/German-statement.tex, + templates/German-work_order.html, + templates/German-work_order.tex, + templates/Hungarian-ap_transaction.html, + templates/Hungarian-ap_transaction.tex, + templates/Hungarian-ar_transaction.html, + templates/Hungarian-ar_transaction.tex, + templates/Hungarian-balance_sheet.html, + templates/Hungarian-bin_list.html, + templates/Hungarian-bin_list.tex, templates/Hungarian-check.tex, + templates/Hungarian-income_statement.html, + templates/Hungarian-invoice.html, + templates/Hungarian-invoice.tex, + templates/Hungarian-packing_list.html, + templates/Hungarian-packing_list.tex, + templates/Hungarian-pick_list.html, + templates/Hungarian-pick_list.tex, + templates/Hungarian-pos_invoice.txt, + templates/Hungarian-purchase_order.html, + templates/Hungarian-purchase_order.tex, + templates/Hungarian-receipt.tex, + templates/Hungarian-request_quotation.html, + templates/Hungarian-request_quotation.tex, + templates/Hungarian-sales_order.html, + templates/Hungarian-sales_order.tex, + templates/Hungarian-sales_quotation.html, + templates/Hungarian-sales_quotation.tex, + templates/Hungarian-statement.html, + templates/Hungarian-statement.tex, + templates/Hungarian-work_order.html, + templates/Hungarian-work_order.tex, + templates/Italian-ap_transaction.html, + templates/Italian-ap_transaction.tex, + templates/Italian-ar_transaction.html, + templates/Italian-ar_transaction.tex, + templates/Italian-balance_sheet.html, + templates/Italian-bin_list.html, templates/Italian-bin_list.tex, + templates/Italian-check.tex, + templates/Italian-income_statement.html, + templates/Italian-invoice.html, templates/Italian-invoice.tex, + templates/Italian-packing_list.html, + templates/Italian-packing_list.tex, + templates/Italian-pick_list.html, + templates/Italian-pick_list.tex, + templates/Italian-pos_invoice.txt, + templates/Italian-purchase_order.html, + templates/Italian-purchase_order.tex, + templates/Italian-receipt.tex, + templates/Italian-request_quotation.html, + templates/Italian-request_quotation.tex, + templates/Italian-sales_order.html, + templates/Italian-sales_order.tex, + templates/Italian-sales_quotation.html, + templates/Italian-sales_quotation.tex, + templates/Italian-statement.html, + templates/Italian-statement.tex, + templates/Italian-work_order.html, + templates/Italian-work_order.tex, + templates/Norwegian-ap_transaction.html, + templates/Norwegian-ap_transaction.tex, + templates/Norwegian-ar_transaction.html, + templates/Norwegian-ar_transaction.tex, + templates/Norwegian-balance_sheet.html, + templates/Norwegian-bin_list.html, + templates/Norwegian-bin_list.tex, templates/Norwegian-check.tex, + templates/Norwegian-income_statement.html, + templates/Norwegian-invoice.html, + templates/Norwegian-invoice.tex, + templates/Norwegian-packing_list.html, + templates/Norwegian-packing_list.tex, + templates/Norwegian-pick_list.html, + templates/Norwegian-pick_list.tex, + templates/Norwegian-pos_invoice.txt, + templates/Norwegian-purchase_order.html, + templates/Norwegian-purchase_order.tex, + templates/Norwegian-receipt.tex, + templates/Norwegian-request_quotation.html, + templates/Norwegian-request_quotation.tex, + templates/Norwegian-sales_order.html, + templates/Norwegian-sales_order.tex, + templates/Norwegian-sales_quotation.html, + templates/Norwegian-sales_quotation.tex, + templates/Norwegian-statement.html, + templates/Norwegian-statement.tex, + templates/Norwegian-work_order.html, + templates/Norwegian-work_order.tex, + templates/Service-ap_transaction.html, + templates/Service-ap_transaction.tex, + templates/Service-ar_transaction.html, + templates/Service-ar_transaction.tex, + templates/Service-balance_sheet.html, + templates/Service-bin_list.html, templates/Service-bin_list.tex, + templates/Service-check.tex, + templates/Service-income_statement.html, + templates/Service-invoice.html, templates/Service-invoice.tex, + templates/Service-packing_list.html, + templates/Service-packing_list.tex, + templates/Service-pick_list.html, + templates/Service-pick_list.tex, + templates/Service-pos_invoice.txt, + templates/Service-purchase_order.html, + templates/Service-purchase_order.tex, + templates/Service-receipt.tex, + templates/Service-request_quotation.html, + templates/Service-request_quotation.tex, + templates/Service-sales_order.html, + templates/Service-sales_order.tex, + templates/Service-sales_quotation.html, + templates/Service-sales_quotation.tex, + templates/Service-statement.html, + templates/Service-statement.tex, + templates/Service-work_order.html, + templates/Service-work_order.tex, + templates/Spanish_A4-ap_transaction.html, + templates/Spanish_A4-ap_transaction.tex, + templates/Spanish_A4-ar_transaction.html, + templates/Spanish_A4-ar_transaction.tex, + templates/Spanish_A4-balance_sheet.html, + templates/Spanish_A4-bin_list.html, + templates/Spanish_A4-bin_list.tex, + templates/Spanish_A4-check.tex, + templates/Spanish_A4-income_statement.html, + templates/Spanish_A4-invoice.html, + templates/Spanish_A4-invoice.tex, + templates/Spanish_A4-packing_list.html, + templates/Spanish_A4-packing_list.tex, + templates/Spanish_A4-pick_list.html, + templates/Spanish_A4-pick_list.tex, + templates/Spanish_A4-pos_invoice.txt, + templates/Spanish_A4-purchase_order.html, + templates/Spanish_A4-purchase_order.tex, + templates/Spanish_A4-receipt.tex, + templates/Spanish_A4-request_quotation.html, + templates/Spanish_A4-request_quotation.tex, + templates/Spanish_A4-sales_order.html, + templates/Spanish_A4-sales_order.tex, + templates/Spanish_A4-sales_quotation.html, + templates/Spanish_A4-sales_quotation.tex, + templates/Spanish_A4-statement.html, + templates/Spanish_A4-statement.tex, + templates/Spanish_A4-work_order.html, + templates/Spanish_A4-work_order.tex, + templates/Spanish_Letter-ap_transaction.html, + templates/Spanish_Letter-ap_transaction.tex, + templates/Spanish_Letter-ar_transaction.html, + templates/Spanish_Letter-ar_transaction.tex, + templates/Spanish_Letter-balance_sheet.html, + templates/Spanish_Letter-bin_list.html, + templates/Spanish_Letter-bin_list.tex, + templates/Spanish_Letter-check.tex, + templates/Spanish_Letter-income_statement.html, + templates/Spanish_Letter-invoice.html, + templates/Spanish_Letter-invoice.tex, + templates/Spanish_Letter-packing_list.html, + templates/Spanish_Letter-packing_list.tex, + templates/Spanish_Letter-pick_list.html, + templates/Spanish_Letter-pick_list.tex, + templates/Spanish_Letter-pos_invoice.txt, + templates/Spanish_Letter-purchase_order.html, + templates/Spanish_Letter-purchase_order.tex, + templates/Spanish_Letter-receipt.tex, + templates/Spanish_Letter-request_quotation.html, + templates/Spanish_Letter-request_quotation.tex, + templates/Spanish_Letter-sales_order.html, + templates/Spanish_Letter-sales_order.tex, + templates/Spanish_Letter-sales_quotation.html, + templates/Spanish_Letter-sales_quotation.tex, + templates/Spanish_Letter-statement.html, + templates/Spanish_Letter-statement.tex, + templates/Spanish_Letter-work_order.html, + templates/Spanish_Letter-work_order.tex, users/sql-ledger.eps, + users/sql-ledger.png: there's no reason this should still be + hanging aroudn the tree + 2007-12-04 12:51 ivan * httemplate/: elements/menu.html, elements/select-otaker.html, @@ -10230,7 +10950,8 @@ FS/FS/Conf.pm, FS/FS/Schema.pm, FS/FS/cust_main.pm, FS/t/svc_acct_rt_transaction.t, httemplate/misc/batch-cust_pay.html, - httemplate/misc/timeworked.html, FS/MANIFEST, + httemplate/misc/timeworked.html, + httemplate/misc/elements/customer-table.html, FS/MANIFEST, httemplate/misc/process/timeworked.html, httemplate/search/timeworked.html, FS/FS/ClientAPI/MyAccount.pm, fs_selfservice/FS-SelfService/cgi/myaccount.html, @@ -11116,6 +11837,13 @@ * FS/FS/cust_pkg.pm: missing method name in docs +2007-07-01 11:26 ivan + + * fs_selfadmin/FS-MailAdminServer/MailAdminClient.pm, + fs_sesmon/FS-SessionClient/SessionClient.pm: this stuff is + probably obsoleted, but get rid of CVS Id tags causing merge pain + anyway + 2007-07-01 11:09 ivan * TODO: remove obsolete information and dollar sign Id dollar sign @@ -11447,6 +12175,30 @@ httemplate/misc/process/link.cgi: 1606 correct bug in overlimit groups handling +2007-05-01 14:49 ivan + + * fs_webdemo/: register.cgi, register.html, registerd, + registerd.Pg: removing 1.4-era web demo signup + +2007-05-01 14:47 ivan + + * fs_radlog/fs_radlogd: removing decade-old fs_radlog (you want + freeside-sqlradius-radacctd now) + +2007-05-01 14:27 ivan + + * install/: centos/3/INSTALL, centos/3/httpd-init, + debian/3.0/INSTALL, debian/3.1/INSTALL, fedora/fc1/INSTALL, + fedora/fc1/sources.list, fedora/fc2/INSTALL, + fedora/fc2/sources.list, fedora/fc3/INSTALL, + fedora/fc3/sources.list, freebsd/INSTALL, freebsd/ports, + openbsd/INSTALL, openbsd/cpan, openbsd/ports, redhat/7.3/INSTALL, + redhat/7.3/sources.list, redhat/8/INSTALL, + redhat/8/README.insecure, redhat/8/sources.list, + redhat/9/INSTALL, redhat/9/sources.list, redhat/es3/INSTALL, + redhat/es3/httpd-init, suse/9.0/INSTALL: remove obsolete install + notes + 2007-05-01 13:00 ivan * FS/FS/ClientAPI/Signup.pm: without debugging this time :) @@ -11861,6 +12613,63 @@ * bin/svc_acct_pop.import: pop import tool +2007-03-09 00:58 ivan + + * install/5.005/: DBD-Pg-1.22-fixvercmp/Changes, + DBD-Pg-1.22-fixvercmp/MANIFEST, + DBD-Pg-1.22-fixvercmp/Makefile.PL, DBD-Pg-1.22-fixvercmp/Pg.h, + DBD-Pg-1.22-fixvercmp/Pg.pm, DBD-Pg-1.22-fixvercmp/Pg.xs, + DBD-Pg-1.22-fixvercmp/README, DBD-Pg-1.22-fixvercmp/README.win32, + DBD-Pg-1.22-fixvercmp/dbd-pg.pod, DBD-Pg-1.22-fixvercmp/dbdimp.c, + DBD-Pg-1.22-fixvercmp/dbdimp.h, + DBD-Pg-1.22-fixvercmp/eg/ApacheDBI.pl, + DBD-Pg-1.22-fixvercmp/eg/lotest.pl, + DBD-Pg-1.22-fixvercmp/eg/notify_test.patch, + DBD-Pg-1.22-fixvercmp/t/00basic.t, + DBD-Pg-1.22-fixvercmp/t/01connect.t, + DBD-Pg-1.22-fixvercmp/t/01constants.t, + DBD-Pg-1.22-fixvercmp/t/01setup.t, + DBD-Pg-1.22-fixvercmp/t/02prepare.t, + DBD-Pg-1.22-fixvercmp/t/03bind.t, + DBD-Pg-1.22-fixvercmp/t/04execute.t, + DBD-Pg-1.22-fixvercmp/t/05fetch.t, + DBD-Pg-1.22-fixvercmp/t/06disconnect.t, + DBD-Pg-1.22-fixvercmp/t/07reuse.t, + DBD-Pg-1.22-fixvercmp/t/08txn.t, + DBD-Pg-1.22-fixvercmp/t/09autocommit.t, + DBD-Pg-1.22-fixvercmp/t/11quoting.t, + DBD-Pg-1.22-fixvercmp/t/12placeholders.t, + DBD-Pg-1.22-fixvercmp/t/13pgtype.t, + DBD-Pg-1.22-fixvercmp/t/15funct.t, + DBD-Pg-1.22-fixvercmp/t/99cleanup.t, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Request.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Util.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler/Prompt.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS/PostgreSQL.pm, + DBIx-DBSchema-0.23-5.005kludge/Changes, + DBIx-DBSchema-0.23-5.005kludge/DBSchema.pm, + DBIx-DBSchema-0.23-5.005kludge/MANIFEST, + DBIx-DBSchema-0.23-5.005kludge/MANIFEST.SKIP, + DBIx-DBSchema-0.23-5.005kludge/Makefile.PL, + DBIx-DBSchema-0.23-5.005kludge/README, + DBIx-DBSchema-0.23-5.005kludge/TODO, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/Column.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/Table.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Index.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Unique.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Pg.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Sybase.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/mysql.pm, + DBIx-DBSchema-0.23-5.005kludge/t/load-mysql.t, + DBIx-DBSchema-0.23-5.005kludge/t/load-pg.t, + DBIx-DBSchema-0.23-5.005kludge/t/load.t: removing old 5.005 + install stuff + 2007-03-07 11:48 khoff * FS/FS/: Conf.pm, cust_main.pm: Option to disable the charging of @@ -15439,6 +16248,11 @@ * httemplate/docs/install.html: add JSON to initial install instructions +2006-04-18 12:24 ivan + + * install/debian/3.1/INSTALL: dev install notes patch from liran + tal + 2006-04-15 06:32 ivan * httemplate/graph/money_time.cgi: REALLY correct the period for @@ -16563,7 +17377,9 @@ 2005-10-15 02:33 ivan - * rt/: etc/RT_SiteConfig.pm, html/Admin/Global/CustomField.html, + * rt/: HOWTO/README, HOWTO/change.txt, HOWTO/release.txt, + HOWTO/version-control.txt, etc/RT_SiteConfig.pm, + html/Admin/Global/CustomField.html, html/Admin/Global/CustomFields.html, html/Elements/Footer, html/Elements/Header, html/Elements/Menu, html/Elements/PageLayout, html/Elements/SimpleSearch, @@ -17004,6 +17820,11 @@ * FS/FS/cust_main.pm: add taxclass kludge to gateway overrides, fix parsing of new-style paybatch +2005-08-17 23:46 ivan + + * install/debian/3.1/INSTALL: slight adjustments to deb install for + latest 1.5.8cvs + 2005-08-17 22:41 ivan * httemplate/edit/process/agent_payment_gateway.html: hopefully @@ -17189,6 +18010,10 @@ * Changelog, Changes.1.5.7: s/ANNOUNCE/Changelog/ +2005-07-11 05:23 ivan + + * install/freebsd/: INSTALL, ports: freebsd install update i guess + 2005-07-11 05:22 ivan * bin/postfix.export: fix regex @@ -17268,7 +18093,8 @@ 2005-06-21 20:54 ivan - * httemplate/docs/upgrade10.html: add IPC::Run3 to install docs + * httemplate/docs/upgrade10.html, install/debian/3.1/INSTALL: add + IPC::Run3 to install docs 2005-06-16 22:31 ivan @@ -17800,6 +18626,15 @@ just needs to update the "seconds" field(s), finally closes: Bug#1125 +2005-04-21 16:13 ivan + + * install/debian/3.1/INSTALL: little bit of apache setup and add + the fs_queue user + +2005-04-21 14:31 ivan + + * install/debian/3.1/INSTALL: or apache won't start + 2005-04-21 04:47 ivan * FS/FS/part_export/acct_sql.pm: fix nit with crypt flag when @@ -17809,6 +18644,10 @@ * FS/FS/part_export/acct_sql.pm: support multiple primary keys +2005-04-20 23:18 ivan + + * install/debian/3.1/INSTALL: libjavascript-rpc-perl hit testing + 2005-04-20 00:12 ivan * FS/FS/part_export/acct_sql.pm: hehe oops @@ -17829,8 +18668,9 @@ 2005-04-19 02:48 ivan * httemplate/docs/install.html, httemplate/docs/upgrade10.html, - ANNOUNCE.1.5, README.1.5.7.lastbit, SCHEMA_CHANGE: did another - upgrade, fixed up the instructions + ANNOUNCE.1.5, README.1.5.7.lastbit, SCHEMA_CHANGE, + install/redhat/9/INSTALL: did another upgrade, fixed up the + instructions 2005-04-19 02:48 ivan @@ -17910,6 +18750,10 @@ * FS/FS/: h_cust_svc.pm, h_svc_forward.pm: No need to inflict debugging messages on everyone. +2005-04-10 14:23 ivan + + * install/debian/3.1/INSTALL: a few more packages + 2005-04-10 06:01 ivan * httemplate/docs/selfservice.html: add apache snippet to @@ -17932,9 +18776,9 @@ 2005-04-07 03:35 ivan - * Makefile, htetc/freeside-base.conf, htetc/freeside-rt.conf: add - install/debian/3.1/INSTALL script and script up some apache - automation assuming a conf.d type dir + * Makefile, htetc/freeside-base.conf, htetc/freeside-rt.conf, + install/debian/3.1/INSTALL: add install/debian/3.1/INSTALL script + and script up some apache automation assuming a conf.d type dir 2005-04-07 02:26 ivan @@ -18107,6 +18951,10 @@ child_objects can now set an alternate field for the svcnum, for things like forwards +2005-03-26 03:51 ivan + + * install/fedora/fc3/: INSTALL, sources.list: fc3 + 2005-03-22 20:16 ivan * httemplate/docs/install-rt.html, README.1.5.7: new RT requires @@ -18268,7 +19116,30 @@ fs_selfservice/FS-SelfService/cgi/signup.cgi, fs_selfservice/FS-SelfService/cgi/signup.html, fs_selfservice/FS-SelfService/cgi/stateselect.html, - fs_selfservice/FS-SelfService/cgi/success.html, htetc/global.asa, + fs_selfservice/FS-SelfService/cgi/success.html, + fs_signup/cck.template, fs_signup/fs_signup_server, + fs_signup/ieak.template, fs_signup/FS-SignupClient/Changes, + fs_signup/FS-SignupClient/MANIFEST, + fs_signup/FS-SignupClient/MANIFEST.SKIP, + fs_signup/FS-SignupClient/Makefile.PL, + fs_signup/FS-SignupClient/SignupClient.pm, + fs_signup/FS-SignupClient/test.pl, + fs_signup/FS-SignupClient/cgi/cvv2.html, + fs_signup/FS-SignupClient/cgi/cvv2.png, + fs_signup/FS-SignupClient/cgi/cvv2_amex.png, + fs_signup/FS-SignupClient/cgi/decline.html, + fs_signup/FS-SignupClient/cgi/map.gif, + fs_signup/FS-SignupClient/cgi/promocode.html, + fs_signup/FS-SignupClient/cgi/regcode.html, + fs_signup/FS-SignupClient/cgi/signup-agentselect.html, + fs_signup/FS-SignupClient/cgi/signup-alternate.html, + fs_signup/FS-SignupClient/cgi/signup-billaddress.html, + fs_signup/FS-SignupClient/cgi/signup-freeoption.html, + fs_signup/FS-SignupClient/cgi/signup-snarf.html, + fs_signup/FS-SignupClient/cgi/signup.cgi, + fs_signup/FS-SignupClient/cgi/signup.html, + fs_signup/FS-SignupClient/cgi/stateselect.html, + fs_signup/FS-SignupClient/cgi/success.html, htetc/global.asa, htetc/handler.pl: - bring prepaid support into this century (close: Bug#1124) - finally get rid of fs_signup (everything is in fs_selfservice now) (Bug#413) - organize main menu sysadmin @@ -18304,6 +19175,10 @@ * FS/FS/XMLRPC.pm: Add the ability to do freeside configuration lookups through the XMLRPC interface. +2005-03-10 07:43 ivan + + * install/freebsd/: INSTALL, ports: ports is a steaming pile + 2005-03-10 07:33 ivan * README.1.5.7, httemplate/docs/install.html, @@ -18330,6 +19205,10 @@ package editing problem with extraneous services showing up, closes: Bug#1170 +2005-03-09 23:27 ivan + + * install/freebsd/INSTALL: freebsd bs + 2005-03-09 00:46 ivan * httemplate/docs/install-rt.html: add complete apache config @@ -18353,6 +19232,11 @@ * FS/FS/XMLRPC.pm: Minor re-work to allow for pseudo methods, like 'version', and eventually config look-ups (next commit). +2005-03-06 03:45 ivan + + * install/freebsd/ports: adding Text::CSV and + Spreadsheet::WriteExcel + 2005-03-06 02:15 ivan * ANNOUNCE.1.5: d @@ -18456,6 +19340,11 @@ * FS/FS/part_pkg/voip_sqlradacct.pm: voip: add start time for calls to invoice details +2005-03-03 00:21 ivan + + * install/redhat/es3/INSTALL: add tetex packages for typeset + invoices + 2005-03-03 00:15 ivan * FS/FS/Record.pm: want a full stack backtrace for this warning @@ -18567,11 +19456,21 @@ * FS/FS/: rate.pm, UI/Web.pm: generalize progressbar code in preparation for using it wherever needed +2005-02-16 14:06 ivan + + * install/centos/3/: INSTALL, httpd-init: centos install notes, + basically like rhell + 2005-02-15 18:53 ivan * FS/FS/cust_bill.pm: slightly better error messages for LaTeX problems +2005-02-15 10:47 ivan + + * install/redhat/es3/INSTALL: update rhell3 docs, add some slony + notes + 2005-02-13 19:49 ivan * FS/FS/svc_acct.pm: this should fix uid duplicate checking, @@ -18597,6 +19496,10 @@ * FS/FS/clientapi_session_field.pm: tyop +2005-02-08 12:51 ivan + + * install/freebsd/: INSTALL, ports: update freebsd install notes + 2005-02-08 12:22 ivan * FS/bin/freeside-setup, httemplate/docs/upgrade10.html, @@ -18632,6 +19535,10 @@ * httemplate/edit/cust_main.cgi: typo +2005-02-04 02:17 ivan + + * install/redhat/es3/INSTALL: minor update for rhel3 install notes + 2005-02-02 00:06 ivan * FS/FS/UI/: Base.pm, CGI.pm, Gtk.pm, agent.pm: removing old UI @@ -18652,6 +19559,9 @@ FS/FS/reg_code.pm, FS/FS/reg_code_pkg.pm, FS/bin/freeside-setup, FS/t/reg_code.t, FS/t/reg_code_pkg.t, README.1.5.0pre7, FS/MANIFEST, FS/FS/ClientAPI/Signup.pm, + fs_signup/FS-SignupClient/cgi/regcode.html, + fs_signup/FS-SignupClient/cgi/signup.cgi, + fs_signup/FS-SignupClient/cgi/signup.html, httemplate/docs/install.html, httemplate/docs/schema.html, httemplate/docs/upgrade10.html, httemplate/edit/reg_code.cgi, httemplate/search/reg_code.html, @@ -19279,15 +20189,24 @@ * FS/FS/cust_pkg.pm: don't check that agent is allowed to purchase the package on changes +2004-12-01 10:38 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: add processing for ship + state/county/country + 2004-11-30 19:35 ivan - * FS/FS/: part_pkg.pm, part_pkg/flat.pm, - part_pkg/flat_comission.pm, part_pkg/flat_comission_cust.pm, - part_pkg/flat_comission_pkg.pm, part_pkg/flat_delayed.pm, - part_pkg/prorate.pm, part_pkg/sesmon_hour.pm, - part_pkg/sesmon_minute.pm, part_pkg/sql_external.pm, - part_pkg/sql_generic.pm, part_pkg/sqlradacct_hour.pm, - part_pkg/subscription.pm, part_pkg/voip_sqlradacct.pm: + * FS/FS/part_pkg.pm, FS/FS/part_pkg/flat.pm, + FS/FS/part_pkg/flat_comission.pm, + FS/FS/part_pkg/flat_comission_cust.pm, + FS/FS/part_pkg/flat_comission_pkg.pm, + FS/FS/part_pkg/flat_delayed.pm, FS/FS/part_pkg/prorate.pm, + FS/FS/part_pkg/sesmon_hour.pm, FS/FS/part_pkg/sesmon_minute.pm, + FS/FS/part_pkg/sql_external.pm, FS/FS/part_pkg/sql_generic.pm, + FS/FS/part_pkg/sqlradacct_hour.pm, + FS/FS/part_pkg/subscription.pm, + FS/FS/part_pkg/voip_sqlradacct.pm, + fs_signup/FS-SignupClient/cgi/signup-freeoption.html: creditcard-less promo code signup 2004-11-30 11:55 khoff @@ -19370,6 +20289,11 @@ FS/bin/freeside-setup, httemplate/docs/schema.html, httemplate/docs/upgrade10.html, FS/FS/Record.pm, FS/FS/cust_pkg.pm, FS/FS/part_pkg.pm, + fs_signup/FS-SignupClient/SignupClient.pm, + fs_signup/FS-SignupClient/cgi/promocode.html, + fs_signup/FS-SignupClient/cgi/signup-billaddress.html, + fs_signup/FS-SignupClient/cgi/signup.cgi, + fs_signup/FS-SignupClient/cgi/signup.html, httemplate/edit/cust_main.cgi, httemplate/edit/part_pkg.cgi: promo codes and separate signup addresses for hdn @@ -19401,6 +20325,38 @@ httemplate/search/sqlradius.cgi, httemplate/search/sqlradius.html: first pass at VoIP rating +2004-11-17 21:06 ivan + + * sql-ledger/: doc/copyright, locale/cn/COPYING, + locale/cn/LANGUAGE, locale/cn/admin, locale/cn/all, locale/cn/am, + locale/cn/ap, locale/cn/ar, locale/cn/arap, locale/cn/ca, + locale/cn/cp, locale/cn/ct, locale/cn/gl, locale/cn/ic, + locale/cn/io, locale/cn/ir, locale/cn/is, locale/cn/login, + locale/cn/menu, locale/cn/oe, locale/cn/pe, locale/cn/rc, + locale/cn/rp, locale/de/all, locale/es/COPYING, + locale/es/LANGUAGE, locale/es/Num2text, locale/es/admin, + locale/es/all, locale/es/am, locale/es/ap, locale/es/ar, + locale/es/arap, locale/es/ca, locale/es/cp, locale/es/ct, + locale/es/gl, locale/es/ic, locale/es/io, locale/es/ir, + locale/es/is, locale/es/login, locale/es/menu, locale/es/oe, + locale/es/pe, locale/es/rc, locale/es/rp, locale/no/COPYING, + locale/no/LANGUAGE, locale/no/admin, locale/no/all, locale/no/am, + locale/no/ap, locale/no/ar, locale/no/arap, locale/no/ca, + locale/no/cp, locale/no/ct, locale/no/gl, locale/no/ic, + locale/no/io, locale/no/ir, locale/no/is, locale/no/login, + locale/no/menu, locale/no/oe, locale/no/pe, locale/no/rc, + locale/no/rp, locale/tw/COPYING, locale/tw/LANGUAGE, + locale/tw/admin, locale/tw/all, locale/tw/am, locale/tw/ap, + locale/tw/ar, locale/tw/arap, locale/tw/ca, locale/tw/cp, + locale/tw/ct, locale/tw/gl, locale/tw/ic, locale/tw/io, + locale/tw/ir, locale/tw/is, locale/tw/login, locale/tw/menu, + locale/tw/oe, locale/tw/pe, locale/tw/rc, locale/tw/rp, + sql/Canada-gifi.sql, sql/Canada_General-chart.sql, + sql/Czech_Republic-chart.sql, sql/Italy-chart.sql, + sql/Simplified_Chinese_Default-chart.sql, sql/Spain-chart.sql, + sql/Traditional_Chinese_Default-chart.sql, users/members.default: + removing files moved in 2.4.4 + 2004-11-17 05:22 ivan * httemplate/edit/part_pkg.cgi: #debugging cruft @@ -19410,6 +20366,566 @@ * httemplate/edit/part_pkg.cgi: fix package options to be sticky on clone-ing (customize package) +2004-11-16 14:12 ivan + + * sql-ledger/: sql-ledger-2.0.8.tar.gz, sql-ledger-2.4.4.tar.gz, + old/sql-ledger/VERSION, old/sql-ledger/am.pl, + old/sql-ledger/favicon.ico, old/sql-ledger/login.pl, + old/sql-ledger/menu.ini, old/sql-ledger/setup.pl, + old/sql-ledger/sql-ledger.conf.default, + old/sql-ledger/sql-ledger.png, old/sql-ledger/SL/AM.pm, + old/sql-ledger/SL/AP.pm, old/sql-ledger/SL/AR.pm, + old/sql-ledger/SL/CA.pm, old/sql-ledger/SL/CP.pm, + old/sql-ledger/SL/CT.pm, old/sql-ledger/SL/Form.pm, + old/sql-ledger/SL/GL.pm, old/sql-ledger/SL/IC.pm, + old/sql-ledger/SL/IR.pm, old/sql-ledger/SL/IS.pm, + old/sql-ledger/SL/Inifile.pm, old/sql-ledger/SL/Mailer.pm, + old/sql-ledger/SL/Menu.pm, old/sql-ledger/SL/Num2text.pm, + old/sql-ledger/SL/OE.pm, old/sql-ledger/SL/PE.pm, + old/sql-ledger/SL/RC.pm, old/sql-ledger/SL/RP.pm, + old/sql-ledger/SL/User.pm, old/sql-ledger/bin/lynx/menu.pl, + old/sql-ledger/bin/mozilla/admin.pl, + old/sql-ledger/bin/mozilla/am.pl, + old/sql-ledger/bin/mozilla/ap.pl, + old/sql-ledger/bin/mozilla/ar.pl, + old/sql-ledger/bin/mozilla/arap.pl, + old/sql-ledger/bin/mozilla/ca.pl, + old/sql-ledger/bin/mozilla/cp.pl, + old/sql-ledger/bin/mozilla/ct.pl, + old/sql-ledger/bin/mozilla/gl.pl, + old/sql-ledger/bin/mozilla/ic.pl, + old/sql-ledger/bin/mozilla/io.pl, + old/sql-ledger/bin/mozilla/ir.pl, + old/sql-ledger/bin/mozilla/is.pl, + old/sql-ledger/bin/mozilla/login.pl, + old/sql-ledger/bin/mozilla/menu.pl, + old/sql-ledger/bin/mozilla/oe.pl, + old/sql-ledger/bin/mozilla/pe.pl, + old/sql-ledger/bin/mozilla/rc.pl, + old/sql-ledger/bin/mozilla/rp.pl, + old/sql-ledger/css/sql-ledger.css, old/sql-ledger/doc/COPYING, + old/sql-ledger/doc/README, old/sql-ledger/doc/UPGRADE-1.6-1.8, + old/sql-ledger/doc/UPGRADE-1.8-1.8.3, + old/sql-ledger/doc/UPGRADE-1.8.3-1.8.4, + old/sql-ledger/doc/UPGRADE-1.8.4-1.8.5, + old/sql-ledger/doc/UPGRADE-1.8.5-1.8.7, + old/sql-ledger/doc/UPGRADE-1.8.7-2.0.0, + old/sql-ledger/doc/UPGRADE-2.0-2.0.8, + old/sql-ledger/doc/copyright, old/sql-ledger/doc/faq.html, + old/sql-ledger/locale/br/COPYING, + old/sql-ledger/locale/br/LANGUAGE, + old/sql-ledger/locale/br/admin, old/sql-ledger/locale/br/all, + old/sql-ledger/locale/br/am, old/sql-ledger/locale/br/ap, + old/sql-ledger/locale/br/ar, old/sql-ledger/locale/br/arap, + old/sql-ledger/locale/br/ca, old/sql-ledger/locale/br/cp, + old/sql-ledger/locale/br/ct, old/sql-ledger/locale/br/gl, + old/sql-ledger/locale/br/ic, old/sql-ledger/locale/br/io, + old/sql-ledger/locale/br/ir, old/sql-ledger/locale/br/is, + old/sql-ledger/locale/br/login, old/sql-ledger/locale/br/menu, + old/sql-ledger/locale/br/oe, old/sql-ledger/locale/br/pe, + old/sql-ledger/locale/br/rc, old/sql-ledger/locale/br/rp, + old/sql-ledger/locale/cn/COPYING, + old/sql-ledger/locale/cn/LANGUAGE, + old/sql-ledger/locale/cn/admin, old/sql-ledger/locale/cn/all, + old/sql-ledger/locale/cn/am, old/sql-ledger/locale/cn/ap, + old/sql-ledger/locale/cn/ar, old/sql-ledger/locale/cn/arap, + old/sql-ledger/locale/cn/ca, old/sql-ledger/locale/cn/cp, + old/sql-ledger/locale/cn/ct, old/sql-ledger/locale/cn/gl, + old/sql-ledger/locale/cn/ic, old/sql-ledger/locale/cn/io, + old/sql-ledger/locale/cn/ir, old/sql-ledger/locale/cn/is, + old/sql-ledger/locale/cn/login, old/sql-ledger/locale/cn/menu, + old/sql-ledger/locale/cn/oe, old/sql-ledger/locale/cn/pe, + old/sql-ledger/locale/cn/rc, old/sql-ledger/locale/cn/rp, + old/sql-ledger/locale/ct/COPYING, + old/sql-ledger/locale/ct/LANGUAGE, + old/sql-ledger/locale/ct/admin, old/sql-ledger/locale/ct/all, + old/sql-ledger/locale/ct/am, old/sql-ledger/locale/ct/ap, + old/sql-ledger/locale/ct/ar, old/sql-ledger/locale/ct/arap, + old/sql-ledger/locale/ct/ca, old/sql-ledger/locale/ct/cp, + old/sql-ledger/locale/ct/ct, old/sql-ledger/locale/ct/gl, + old/sql-ledger/locale/ct/ic, old/sql-ledger/locale/ct/io, + old/sql-ledger/locale/ct/ir, old/sql-ledger/locale/ct/is, + old/sql-ledger/locale/ct/login, old/sql-ledger/locale/ct/menu, + old/sql-ledger/locale/ct/oe, old/sql-ledger/locale/ct/pe, + old/sql-ledger/locale/ct/rc, old/sql-ledger/locale/ct/rp, + old/sql-ledger/locale/cz/COPYING, + old/sql-ledger/locale/cz/LANGUAGE, + old/sql-ledger/locale/cz/admin, old/sql-ledger/locale/cz/all, + old/sql-ledger/locale/cz/am, old/sql-ledger/locale/cz/ap, + old/sql-ledger/locale/cz/ar, old/sql-ledger/locale/cz/arap, + old/sql-ledger/locale/cz/ca, old/sql-ledger/locale/cz/cp, + old/sql-ledger/locale/cz/ct, old/sql-ledger/locale/cz/gl, + old/sql-ledger/locale/cz/ic, old/sql-ledger/locale/cz/io, + old/sql-ledger/locale/cz/ir, old/sql-ledger/locale/cz/is, + old/sql-ledger/locale/cz/login, old/sql-ledger/locale/cz/menu, + old/sql-ledger/locale/cz/oe, old/sql-ledger/locale/cz/pe, + old/sql-ledger/locale/cz/rc, old/sql-ledger/locale/cz/rp, + old/sql-ledger/locale/de/COPYING, + old/sql-ledger/locale/de/LANGUAGE, + old/sql-ledger/locale/de/Num2text, + old/sql-ledger/locale/de/admin, old/sql-ledger/locale/de/all, + old/sql-ledger/locale/de/am, old/sql-ledger/locale/de/ap, + old/sql-ledger/locale/de/ar, old/sql-ledger/locale/de/arap, + old/sql-ledger/locale/de/ca, old/sql-ledger/locale/de/cp, + old/sql-ledger/locale/de/ct, old/sql-ledger/locale/de/gl, + old/sql-ledger/locale/de/ic, old/sql-ledger/locale/de/io, + old/sql-ledger/locale/de/ir, old/sql-ledger/locale/de/is, + old/sql-ledger/locale/de/locales.pl, + old/sql-ledger/locale/de/login, old/sql-ledger/locale/de/menu, + old/sql-ledger/locale/de/oe, old/sql-ledger/locale/de/pe, + old/sql-ledger/locale/de/rc, old/sql-ledger/locale/de/rp, + old/sql-ledger/locale/dk/COPYING, + old/sql-ledger/locale/dk/LANGUAGE, + old/sql-ledger/locale/dk/admin, old/sql-ledger/locale/dk/all, + old/sql-ledger/locale/dk/am, old/sql-ledger/locale/dk/ap, + old/sql-ledger/locale/dk/ar, old/sql-ledger/locale/dk/arap, + old/sql-ledger/locale/dk/ca, old/sql-ledger/locale/dk/cp, + old/sql-ledger/locale/dk/ct, old/sql-ledger/locale/dk/gl, + old/sql-ledger/locale/dk/ic, old/sql-ledger/locale/dk/io, + old/sql-ledger/locale/dk/ir, old/sql-ledger/locale/dk/is, + old/sql-ledger/locale/dk/login, old/sql-ledger/locale/dk/menu, + old/sql-ledger/locale/dk/oe, old/sql-ledger/locale/dk/pe, + old/sql-ledger/locale/dk/rc, old/sql-ledger/locale/dk/rp, + old/sql-ledger/locale/ee/COPYING, + old/sql-ledger/locale/ee/LANGUAGE, + old/sql-ledger/locale/ee/admin, old/sql-ledger/locale/ee/all, + old/sql-ledger/locale/ee/am, old/sql-ledger/locale/ee/ap, + old/sql-ledger/locale/ee/ar, old/sql-ledger/locale/ee/arap, + old/sql-ledger/locale/ee/ca, old/sql-ledger/locale/ee/cp, + old/sql-ledger/locale/ee/ct, old/sql-ledger/locale/ee/gl, + old/sql-ledger/locale/ee/ic, old/sql-ledger/locale/ee/io, + old/sql-ledger/locale/ee/ir, old/sql-ledger/locale/ee/is, + old/sql-ledger/locale/ee/login, old/sql-ledger/locale/ee/menu, + old/sql-ledger/locale/ee/oe, old/sql-ledger/locale/ee/pe, + old/sql-ledger/locale/ee/rc, old/sql-ledger/locale/ee/rp, + old/sql-ledger/locale/en_GB/COPYING, + old/sql-ledger/locale/en_GB/LANGUAGE, + old/sql-ledger/locale/en_GB/admin, + old/sql-ledger/locale/en_GB/all, old/sql-ledger/locale/en_GB/am, + old/sql-ledger/locale/en_GB/ap, old/sql-ledger/locale/en_GB/ar, + old/sql-ledger/locale/en_GB/arap, old/sql-ledger/locale/en_GB/bp, + old/sql-ledger/locale/en_GB/ca, old/sql-ledger/locale/en_GB/cp, + old/sql-ledger/locale/en_GB/ct, old/sql-ledger/locale/en_GB/gl, + old/sql-ledger/locale/en_GB/ic, old/sql-ledger/locale/en_GB/io, + old/sql-ledger/locale/en_GB/ir, old/sql-ledger/locale/en_GB/is, + old/sql-ledger/locale/en_GB/login, + old/sql-ledger/locale/en_GB/menu, old/sql-ledger/locale/en_GB/oe, + old/sql-ledger/locale/en_GB/pe, old/sql-ledger/locale/en_GB/rc, + old/sql-ledger/locale/en_GB/rp, old/sql-ledger/locale/es/COPYING, + old/sql-ledger/locale/es/LANGUAGE, + old/sql-ledger/locale/es/Num2text, + old/sql-ledger/locale/es/admin, old/sql-ledger/locale/es/all, + old/sql-ledger/locale/es/am, old/sql-ledger/locale/es/ap, + old/sql-ledger/locale/es/ar, old/sql-ledger/locale/es/arap, + old/sql-ledger/locale/es/ca, old/sql-ledger/locale/es/cp, + old/sql-ledger/locale/es/ct, old/sql-ledger/locale/es/gl, + old/sql-ledger/locale/es/ic, old/sql-ledger/locale/es/io, + old/sql-ledger/locale/es/ir, old/sql-ledger/locale/es/is, + old/sql-ledger/locale/es/login, old/sql-ledger/locale/es/menu, + old/sql-ledger/locale/es/oe, old/sql-ledger/locale/es/pe, + old/sql-ledger/locale/es/rc, old/sql-ledger/locale/es/rp, + old/sql-ledger/locale/fi/COPYING, + old/sql-ledger/locale/fi/LANGUAGE, + old/sql-ledger/locale/fi/admin, old/sql-ledger/locale/fi/all, + old/sql-ledger/locale/fi/am, old/sql-ledger/locale/fi/ap, + old/sql-ledger/locale/fi/ar, old/sql-ledger/locale/fi/arap, + old/sql-ledger/locale/fi/ca, old/sql-ledger/locale/fi/cp, + old/sql-ledger/locale/fi/ct, old/sql-ledger/locale/fi/gl, + old/sql-ledger/locale/fi/ic, old/sql-ledger/locale/fi/io, + old/sql-ledger/locale/fi/ir, old/sql-ledger/locale/fi/is, + old/sql-ledger/locale/fi/login, old/sql-ledger/locale/fi/menu, + old/sql-ledger/locale/fi/oe, old/sql-ledger/locale/fi/pe, + old/sql-ledger/locale/fi/rc, old/sql-ledger/locale/fi/rp, + old/sql-ledger/locale/fr/COPYING, + old/sql-ledger/locale/fr/LANGUAGE, + old/sql-ledger/locale/fr/admin, old/sql-ledger/locale/fr/all, + old/sql-ledger/locale/fr/am, old/sql-ledger/locale/fr/ap, + old/sql-ledger/locale/fr/ar, old/sql-ledger/locale/fr/arap, + old/sql-ledger/locale/fr/ca, old/sql-ledger/locale/fr/cp, + old/sql-ledger/locale/fr/ct, old/sql-ledger/locale/fr/gl, + old/sql-ledger/locale/fr/ic, old/sql-ledger/locale/fr/io, + old/sql-ledger/locale/fr/ir, old/sql-ledger/locale/fr/is, + old/sql-ledger/locale/fr/login, old/sql-ledger/locale/fr/menu, + old/sql-ledger/locale/fr/oe, old/sql-ledger/locale/fr/pe, + old/sql-ledger/locale/fr/rc, old/sql-ledger/locale/fr/rp, + old/sql-ledger/locale/hu/COPYING, + old/sql-ledger/locale/hu/LANGUAGE, + old/sql-ledger/locale/hu/admin, old/sql-ledger/locale/hu/all, + old/sql-ledger/locale/hu/am, old/sql-ledger/locale/hu/ap, + old/sql-ledger/locale/hu/ar, old/sql-ledger/locale/hu/arap, + old/sql-ledger/locale/hu/ca, old/sql-ledger/locale/hu/cp, + old/sql-ledger/locale/hu/ct, old/sql-ledger/locale/hu/gl, + old/sql-ledger/locale/hu/ic, old/sql-ledger/locale/hu/io, + old/sql-ledger/locale/hu/ir, old/sql-ledger/locale/hu/is, + old/sql-ledger/locale/hu/login, old/sql-ledger/locale/hu/menu, + old/sql-ledger/locale/hu/oe, old/sql-ledger/locale/hu/pe, + old/sql-ledger/locale/hu/rc, old/sql-ledger/locale/hu/rp, + old/sql-ledger/locale/is/COPYING, + old/sql-ledger/locale/is/LANGUAGE, + old/sql-ledger/locale/is/admin, old/sql-ledger/locale/is/all, + old/sql-ledger/locale/is/am, old/sql-ledger/locale/is/ap, + old/sql-ledger/locale/is/ar, old/sql-ledger/locale/is/arap, + old/sql-ledger/locale/is/ca, old/sql-ledger/locale/is/cp, + old/sql-ledger/locale/is/ct, old/sql-ledger/locale/is/gl, + old/sql-ledger/locale/is/ic, old/sql-ledger/locale/is/io, + old/sql-ledger/locale/is/ir, old/sql-ledger/locale/is/is, + old/sql-ledger/locale/is/login, old/sql-ledger/locale/is/menu, + old/sql-ledger/locale/is/oe, old/sql-ledger/locale/is/pe, + old/sql-ledger/locale/is/rc, old/sql-ledger/locale/is/rp, + old/sql-ledger/locale/it/COPYING, + old/sql-ledger/locale/it/LANGUAGE, + old/sql-ledger/locale/it/Num2text, + old/sql-ledger/locale/it/admin, old/sql-ledger/locale/it/all, + old/sql-ledger/locale/it/am, old/sql-ledger/locale/it/ap, + old/sql-ledger/locale/it/ar, old/sql-ledger/locale/it/arap, + old/sql-ledger/locale/it/ca, old/sql-ledger/locale/it/cp, + old/sql-ledger/locale/it/ct, old/sql-ledger/locale/it/gl, + old/sql-ledger/locale/it/ic, old/sql-ledger/locale/it/io, + old/sql-ledger/locale/it/ir, old/sql-ledger/locale/it/is, + old/sql-ledger/locale/it/login, old/sql-ledger/locale/it/menu, + old/sql-ledger/locale/it/oe, old/sql-ledger/locale/it/pe, + old/sql-ledger/locale/it/qe, old/sql-ledger/locale/it/rc, + old/sql-ledger/locale/it/rp, old/sql-ledger/locale/lt/COPYING, + old/sql-ledger/locale/lt/LANGUAGE, + old/sql-ledger/locale/lt/admin, old/sql-ledger/locale/lt/all, + old/sql-ledger/locale/lt/am, old/sql-ledger/locale/lt/ap, + old/sql-ledger/locale/lt/ar, old/sql-ledger/locale/lt/arap, + old/sql-ledger/locale/lt/ca, old/sql-ledger/locale/lt/cp, + old/sql-ledger/locale/lt/ct, old/sql-ledger/locale/lt/gl, + old/sql-ledger/locale/lt/ic, old/sql-ledger/locale/lt/io, + old/sql-ledger/locale/lt/ir, old/sql-ledger/locale/lt/is, + old/sql-ledger/locale/lt/login, old/sql-ledger/locale/lt/menu, + old/sql-ledger/locale/lt/oe, old/sql-ledger/locale/lt/pe, + old/sql-ledger/locale/lt/rc, old/sql-ledger/locale/lt/rp, + old/sql-ledger/locale/mx/COPYING, + old/sql-ledger/locale/mx/LANGUAGE, + old/sql-ledger/locale/mx/admin, old/sql-ledger/locale/mx/all, + old/sql-ledger/locale/mx/am, old/sql-ledger/locale/mx/ap, + old/sql-ledger/locale/mx/ar, old/sql-ledger/locale/mx/arap, + old/sql-ledger/locale/mx/ca, old/sql-ledger/locale/mx/cp, + old/sql-ledger/locale/mx/ct, old/sql-ledger/locale/mx/gl, + old/sql-ledger/locale/mx/ic, old/sql-ledger/locale/mx/io, + old/sql-ledger/locale/mx/ir, old/sql-ledger/locale/mx/is, + old/sql-ledger/locale/mx/login, old/sql-ledger/locale/mx/menu, + old/sql-ledger/locale/mx/oe, old/sql-ledger/locale/mx/pe, + old/sql-ledger/locale/mx/rc, old/sql-ledger/locale/mx/rp, + old/sql-ledger/locale/nl/COPYING, + old/sql-ledger/locale/nl/LANGUAGE, + old/sql-ledger/locale/nl/Num2text, + old/sql-ledger/locale/nl/admin, old/sql-ledger/locale/nl/all, + old/sql-ledger/locale/nl/am, old/sql-ledger/locale/nl/ap, + old/sql-ledger/locale/nl/ar, old/sql-ledger/locale/nl/arap, + old/sql-ledger/locale/nl/ca, old/sql-ledger/locale/nl/cp, + old/sql-ledger/locale/nl/ct, old/sql-ledger/locale/nl/gl, + old/sql-ledger/locale/nl/ic, old/sql-ledger/locale/nl/io, + old/sql-ledger/locale/nl/ir, old/sql-ledger/locale/nl/is, + old/sql-ledger/locale/nl/login, old/sql-ledger/locale/nl/menu, + old/sql-ledger/locale/nl/oe, old/sql-ledger/locale/nl/pe, + old/sql-ledger/locale/nl/rc, old/sql-ledger/locale/nl/rp, + old/sql-ledger/locale/no/COPYING, + old/sql-ledger/locale/no/LANGUAGE, + old/sql-ledger/locale/no/admin, old/sql-ledger/locale/no/all, + old/sql-ledger/locale/no/am, old/sql-ledger/locale/no/ap, + old/sql-ledger/locale/no/ar, old/sql-ledger/locale/no/arap, + old/sql-ledger/locale/no/ca, old/sql-ledger/locale/no/cp, + old/sql-ledger/locale/no/ct, old/sql-ledger/locale/no/gl, + old/sql-ledger/locale/no/ic, old/sql-ledger/locale/no/io, + old/sql-ledger/locale/no/ir, old/sql-ledger/locale/no/is, + old/sql-ledger/locale/no/login, old/sql-ledger/locale/no/menu, + old/sql-ledger/locale/no/oe, old/sql-ledger/locale/no/pe, + old/sql-ledger/locale/no/rc, old/sql-ledger/locale/no/rp, + old/sql-ledger/locale/pa/COPYING, + old/sql-ledger/locale/pa/LANGUAGE, + old/sql-ledger/locale/pa/admin, old/sql-ledger/locale/pa/all, + old/sql-ledger/locale/pa/am, old/sql-ledger/locale/pa/ap, + old/sql-ledger/locale/pa/ar, old/sql-ledger/locale/pa/arap, + old/sql-ledger/locale/pa/ca, old/sql-ledger/locale/pa/cp, + old/sql-ledger/locale/pa/ct, old/sql-ledger/locale/pa/gl, + old/sql-ledger/locale/pa/ic, old/sql-ledger/locale/pa/io, + old/sql-ledger/locale/pa/ir, old/sql-ledger/locale/pa/is, + old/sql-ledger/locale/pa/login, old/sql-ledger/locale/pa/menu, + old/sql-ledger/locale/pa/oe, old/sql-ledger/locale/pa/pe, + old/sql-ledger/locale/pa/rc, old/sql-ledger/locale/pa/rp, + old/sql-ledger/locale/pl/COPYING, + old/sql-ledger/locale/pl/LANGUAGE, + old/sql-ledger/locale/pl/admin, old/sql-ledger/locale/pl/all, + old/sql-ledger/locale/pl/am, old/sql-ledger/locale/pl/ap, + old/sql-ledger/locale/pl/ar, old/sql-ledger/locale/pl/arap, + old/sql-ledger/locale/pl/ca, old/sql-ledger/locale/pl/cp, + old/sql-ledger/locale/pl/ct, old/sql-ledger/locale/pl/gl, + old/sql-ledger/locale/pl/ic, old/sql-ledger/locale/pl/io, + old/sql-ledger/locale/pl/ir, old/sql-ledger/locale/pl/is, + old/sql-ledger/locale/pl/login, old/sql-ledger/locale/pl/menu, + old/sql-ledger/locale/pl/oe, old/sql-ledger/locale/pl/pe, + old/sql-ledger/locale/pl/rc, old/sql-ledger/locale/pl/rp, + old/sql-ledger/locale/pt/COPYING, + old/sql-ledger/locale/pt/LANGUAGE, + old/sql-ledger/locale/pt/admin, old/sql-ledger/locale/pt/all, + old/sql-ledger/locale/pt/am, old/sql-ledger/locale/pt/ap, + old/sql-ledger/locale/pt/ar, old/sql-ledger/locale/pt/arap, + old/sql-ledger/locale/pt/ca, old/sql-ledger/locale/pt/cp, + old/sql-ledger/locale/pt/ct, old/sql-ledger/locale/pt/gl, + old/sql-ledger/locale/pt/ic, old/sql-ledger/locale/pt/io, + old/sql-ledger/locale/pt/ir, old/sql-ledger/locale/pt/is, + old/sql-ledger/locale/pt/login, old/sql-ledger/locale/pt/menu, + old/sql-ledger/locale/pt/oe, old/sql-ledger/locale/pt/pe, + old/sql-ledger/locale/pt/rc, old/sql-ledger/locale/pt/rp, + old/sql-ledger/locale/ru/COPYING, + old/sql-ledger/locale/ru/LANGUAGE, + old/sql-ledger/locale/ru/admin, old/sql-ledger/locale/ru/all, + old/sql-ledger/locale/ru/am, old/sql-ledger/locale/ru/ap, + old/sql-ledger/locale/ru/ar, old/sql-ledger/locale/ru/arap, + old/sql-ledger/locale/ru/ca, old/sql-ledger/locale/ru/cp, + old/sql-ledger/locale/ru/ct, old/sql-ledger/locale/ru/gl, + old/sql-ledger/locale/ru/ic, old/sql-ledger/locale/ru/io, + old/sql-ledger/locale/ru/ir, old/sql-ledger/locale/ru/is, + old/sql-ledger/locale/ru/login, old/sql-ledger/locale/ru/menu, + old/sql-ledger/locale/ru/oe, old/sql-ledger/locale/ru/pe, + old/sql-ledger/locale/ru/rc, old/sql-ledger/locale/ru/rp, + old/sql-ledger/locale/se/COPYING, + old/sql-ledger/locale/se/LANGUAGE, + old/sql-ledger/locale/se/admin, old/sql-ledger/locale/se/all, + old/sql-ledger/locale/se/am, old/sql-ledger/locale/se/ap, + old/sql-ledger/locale/se/ar, old/sql-ledger/locale/se/arap, + old/sql-ledger/locale/se/ca, old/sql-ledger/locale/se/cp, + old/sql-ledger/locale/se/ct, old/sql-ledger/locale/se/gl, + old/sql-ledger/locale/se/ic, old/sql-ledger/locale/se/io, + old/sql-ledger/locale/se/ir, old/sql-ledger/locale/se/is, + old/sql-ledger/locale/se/login, old/sql-ledger/locale/se/menu, + old/sql-ledger/locale/se/oe, old/sql-ledger/locale/se/pe, + old/sql-ledger/locale/se/rc, old/sql-ledger/locale/se/rp, + old/sql-ledger/locale/tr/COPYING, + old/sql-ledger/locale/tr/LANGUAGE, + old/sql-ledger/locale/tr/admin, old/sql-ledger/locale/tr/all, + old/sql-ledger/locale/tr/am, old/sql-ledger/locale/tr/ap, + old/sql-ledger/locale/tr/ar, old/sql-ledger/locale/tr/arap, + old/sql-ledger/locale/tr/ca, old/sql-ledger/locale/tr/cp, + old/sql-ledger/locale/tr/ct, old/sql-ledger/locale/tr/gl, + old/sql-ledger/locale/tr/ic, old/sql-ledger/locale/tr/io, + old/sql-ledger/locale/tr/ir, old/sql-ledger/locale/tr/is, + old/sql-ledger/locale/tr/login, old/sql-ledger/locale/tr/menu, + old/sql-ledger/locale/tr/oe, old/sql-ledger/locale/tr/pe, + old/sql-ledger/locale/tr/rc, old/sql-ledger/locale/tr/rp, + old/sql-ledger/locale/tw/COPYING, + old/sql-ledger/locale/tw/LANGUAGE, + old/sql-ledger/locale/tw/admin, old/sql-ledger/locale/tw/all, + old/sql-ledger/locale/tw/am, old/sql-ledger/locale/tw/ap, + old/sql-ledger/locale/tw/ar, old/sql-ledger/locale/tw/arap, + old/sql-ledger/locale/tw/ca, old/sql-ledger/locale/tw/cp, + old/sql-ledger/locale/tw/ct, old/sql-ledger/locale/tw/gl, + old/sql-ledger/locale/tw/ic, old/sql-ledger/locale/tw/io, + old/sql-ledger/locale/tw/ir, old/sql-ledger/locale/tw/is, + old/sql-ledger/locale/tw/login, old/sql-ledger/locale/tw/menu, + old/sql-ledger/locale/tw/oe, old/sql-ledger/locale/tw/pe, + old/sql-ledger/locale/tw/rc, old/sql-ledger/locale/tw/rp, + old/sql-ledger/locale/ua/COPYING, + old/sql-ledger/locale/ua/LANGUAGE, + old/sql-ledger/locale/ua/admin, old/sql-ledger/locale/ua/all, + old/sql-ledger/locale/ua/am, old/sql-ledger/locale/ua/ap, + old/sql-ledger/locale/ua/ar, old/sql-ledger/locale/ua/arap, + old/sql-ledger/locale/ua/ca, old/sql-ledger/locale/ua/cp, + old/sql-ledger/locale/ua/ct, old/sql-ledger/locale/ua/gl, + old/sql-ledger/locale/ua/ic, old/sql-ledger/locale/ua/io, + old/sql-ledger/locale/ua/ir, old/sql-ledger/locale/ua/is, + old/sql-ledger/locale/ua/login, old/sql-ledger/locale/ua/menu, + old/sql-ledger/locale/ua/oe, old/sql-ledger/locale/ua/pe, + old/sql-ledger/locale/ua/rc, old/sql-ledger/locale/ua/rp, + old/sql-ledger/locale/ve/COPYING, + old/sql-ledger/locale/ve/LANGUAGE, + old/sql-ledger/locale/ve/admin, old/sql-ledger/locale/ve/all, + old/sql-ledger/locale/ve/am, old/sql-ledger/locale/ve/ap, + old/sql-ledger/locale/ve/ar, old/sql-ledger/locale/ve/arap, + old/sql-ledger/locale/ve/ca, old/sql-ledger/locale/ve/cp, + old/sql-ledger/locale/ve/ct, old/sql-ledger/locale/ve/gl, + old/sql-ledger/locale/ve/ic, old/sql-ledger/locale/ve/io, + old/sql-ledger/locale/ve/ir, old/sql-ledger/locale/ve/is, + old/sql-ledger/locale/ve/login, old/sql-ledger/locale/ve/menu, + old/sql-ledger/locale/ve/oe, old/sql-ledger/locale/ve/pe, + old/sql-ledger/locale/ve/rc, old/sql-ledger/locale/ve/rp, + old/sql-ledger/sql/Austria-chart.sql, + old/sql-ledger/sql/Austria-gifi.sql, + old/sql-ledger/sql/Brazil_General-chart.sql, + old/sql-ledger/sql/Canada-gifi.sql, + old/sql-ledger/sql/Canada_General-chart.sql, + old/sql-ledger/sql/Czech_Republic-chart.sql, + old/sql-ledger/sql/Danish_Default-chart.sql, + old/sql-ledger/sql/Default-chart.sql, + old/sql-ledger/sql/Dutch_Default-chart.sql, + old/sql-ledger/sql/Dutch_Standard-chart.sql, + old/sql-ledger/sql/France-chart.sql, + old/sql-ledger/sql/German-Sample-chart.sql, + old/sql-ledger/sql/German-Sample-gifi.sql, + old/sql-ledger/sql/Germany-DATEV-SKR03-chart.sql, + old/sql-ledger/sql/Germany-DATEV-SKR03-gifi.sql, + old/sql-ledger/sql/Germany-SKR03-chart.sql, + old/sql-ledger/sql/Germany-SKR03-gifi.sql, + old/sql-ledger/sql/Italy-chart.sql, + old/sql-ledger/sql/Oracle-indices.sql, + old/sql-ledger/sql/Oracle-tables.sql, + old/sql-ledger/sql/Oracle-upgrade-1.8.0-1.8.4.sql, + old/sql-ledger/sql/Oracle-upgrade-1.8.4-1.8.5.sql, + old/sql-ledger/sql/Oracle-upgrade-1.8.5-2.0.0.sql, + old/sql-ledger/sql/Oracle-upgrade-2.0.0-2.0.8.sql, + old/sql-ledger/sql/Pg-indices.sql, + old/sql-ledger/sql/Pg-tables.sql, + old/sql-ledger/sql/Pg-upgrade-1.2.6-1.2.7.sql, + old/sql-ledger/sql/Pg-upgrade-1.2.7-1.4.0.sql, + old/sql-ledger/sql/Pg-upgrade-1.4.0-1.6.0.sql, + old/sql-ledger/sql/Pg-upgrade-1.6.0-1.8.0.sql, + old/sql-ledger/sql/Pg-upgrade-1.8.0-1.8.4.sql, + old/sql-ledger/sql/Pg-upgrade-1.8.4-1.8.5.sql, + old/sql-ledger/sql/Pg-upgrade-1.8.5-2.0.0.sql, + old/sql-ledger/sql/Pg-upgrade-2.0.0-2.0.8.sql, + old/sql-ledger/sql/Poland-chart.sql, + old/sql-ledger/sql/Simplified_Chinese_Default-chart.sql, + old/sql-ledger/sql/Spain-chart.sql, + old/sql-ledger/sql/Swiss-German-chart.sql, + old/sql-ledger/sql/Swiss-German-gifi.sql, + old/sql-ledger/sql/Traditional_Chinese_Default-chart.sql, + old/sql-ledger/sql/US_General-chart.sql, + old/sql-ledger/templates/Brazilian_Portuguese-balance_sheet.html, + old/sql-ledger/templates/Brazilian_Portuguese-check.tex, + old/sql-ledger/templates/Brazilian_Portuguese-income_statement.html, + old/sql-ledger/templates/Brazilian_Portuguese-invoice.html, + old/sql-ledger/templates/Brazilian_Portuguese-invoice.tex, + old/sql-ledger/templates/Brazilian_Portuguese-packing_list.html, + old/sql-ledger/templates/Brazilian_Portuguese-packing_list.tex, + old/sql-ledger/templates/Brazilian_Portuguese-purchase_order.html, + old/sql-ledger/templates/Brazilian_Portuguese-purchase_order.tex, + old/sql-ledger/templates/Brazilian_Portuguese-receipt.tex, + old/sql-ledger/templates/Brazilian_Portuguese-sales_order.html, + old/sql-ledger/templates/Brazilian_Portuguese-sales_order.tex, + old/sql-ledger/templates/Brazilian_Portuguese-statement.html, + old/sql-ledger/templates/Brazilian_Portuguese-statement.tex, + old/sql-ledger/templates/Danish-balance_sheet.html, + old/sql-ledger/templates/Danish-check.tex, + old/sql-ledger/templates/Danish-income_statement.html, + old/sql-ledger/templates/Danish-invoice.html, + old/sql-ledger/templates/Danish-invoice.tex, + old/sql-ledger/templates/Danish-packing_list.html, + old/sql-ledger/templates/Danish-packing_list.tex, + old/sql-ledger/templates/Danish-purchase_order.html, + old/sql-ledger/templates/Danish-purchase_order.tex, + old/sql-ledger/templates/Danish-receipt.tex, + old/sql-ledger/templates/Danish-sales_order.html, + old/sql-ledger/templates/Danish-sales_order.tex, + old/sql-ledger/templates/Danish-statement.html, + old/sql-ledger/templates/Danish-statement.tex, + old/sql-ledger/templates/Default-balance_sheet.html, + old/sql-ledger/templates/Default-check.tex, + old/sql-ledger/templates/Default-income_statement.html, + old/sql-ledger/templates/Default-invoice.html, + old/sql-ledger/templates/Default-invoice.tex, + old/sql-ledger/templates/Default-packing_list.html, + old/sql-ledger/templates/Default-packing_list.tex, + old/sql-ledger/templates/Default-purchase_order.html, + old/sql-ledger/templates/Default-purchase_order.tex, + old/sql-ledger/templates/Default-receipt.tex, + old/sql-ledger/templates/Default-sales_order.html, + old/sql-ledger/templates/Default-sales_order.tex, + old/sql-ledger/templates/Default-statement.html, + old/sql-ledger/templates/Default-statement.tex, + old/sql-ledger/templates/Dutch-balance_sheet.html, + old/sql-ledger/templates/Dutch-check.tex, + old/sql-ledger/templates/Dutch-income_statement.html, + old/sql-ledger/templates/Dutch-invoice.html, + old/sql-ledger/templates/Dutch-invoice.tex, + old/sql-ledger/templates/Dutch-packing_list.html, + old/sql-ledger/templates/Dutch-packing_list.tex, + old/sql-ledger/templates/Dutch-purchase_order.html, + old/sql-ledger/templates/Dutch-purchase_order.tex, + old/sql-ledger/templates/Dutch-receipt.tex, + old/sql-ledger/templates/Dutch-sales_order.html, + old/sql-ledger/templates/Dutch-sales_order.tex, + old/sql-ledger/templates/Dutch-statement.html, + old/sql-ledger/templates/Dutch-statement.tex, + old/sql-ledger/templates/Estonian-balance_sheet.html, + old/sql-ledger/templates/Estonian-check.tex, + old/sql-ledger/templates/Estonian-income_statement.html, + old/sql-ledger/templates/Estonian-invoice.html, + old/sql-ledger/templates/Estonian-invoice.tex, + old/sql-ledger/templates/Estonian-packing_list.html, + old/sql-ledger/templates/Estonian-packing_list.tex, + old/sql-ledger/templates/Estonian-purchase_order.html, + old/sql-ledger/templates/Estonian-purchase_order.tex, + old/sql-ledger/templates/Estonian-receipt.tex, + old/sql-ledger/templates/Estonian-sales_order.html, + old/sql-ledger/templates/Estonian-sales_order.tex, + old/sql-ledger/templates/Estonian-statement.html, + old/sql-ledger/templates/Estonian-statement.tex, + old/sql-ledger/templates/French-balance_sheet.html, + old/sql-ledger/templates/French-check.tex, + old/sql-ledger/templates/French-income_statement.html, + old/sql-ledger/templates/French-invoice.html, + old/sql-ledger/templates/French-invoice.tex, + old/sql-ledger/templates/French-packing_list.html, + old/sql-ledger/templates/French-packing_list.tex, + old/sql-ledger/templates/French-purchase_order.html, + old/sql-ledger/templates/French-purchase_order.tex, + old/sql-ledger/templates/French-receipt.tex, + old/sql-ledger/templates/French-sales_order.html, + old/sql-ledger/templates/French-sales_order.tex, + old/sql-ledger/templates/French-statement.html, + old/sql-ledger/templates/French-statement.tex, + old/sql-ledger/templates/German-balance_sheet.html, + old/sql-ledger/templates/German-check.tex, + old/sql-ledger/templates/German-income_statement.html, + old/sql-ledger/templates/German-invoice.html, + old/sql-ledger/templates/German-invoice.tex, + old/sql-ledger/templates/German-packing_list.html, + old/sql-ledger/templates/German-packing_list.tex, + old/sql-ledger/templates/German-purchase_order.html, + old/sql-ledger/templates/German-purchase_order.tex, + old/sql-ledger/templates/German-receipt.tex, + old/sql-ledger/templates/German-sales_order.html, + old/sql-ledger/templates/German-sales_order.tex, + old/sql-ledger/templates/German-statement.html, + old/sql-ledger/templates/German-statement.tex, + old/sql-ledger/templates/Service-balance_sheet.html, + old/sql-ledger/templates/Service-check.tex, + old/sql-ledger/templates/Service-income_statement.html, + old/sql-ledger/templates/Service-invoice.html, + old/sql-ledger/templates/Service-invoice.tex, + old/sql-ledger/templates/Service-packing_list.html, + old/sql-ledger/templates/Service-packing_list.tex, + old/sql-ledger/templates/Service-purchase_order.html, + old/sql-ledger/templates/Service-purchase_order.tex, + old/sql-ledger/templates/Service-receipt.tex, + old/sql-ledger/templates/Service-sales_order.html, + old/sql-ledger/templates/Service-sales_order.tex, + old/sql-ledger/templates/Service-statement.html, + old/sql-ledger/templates/Service-statement.tex, + old/sql-ledger/templates/Spanish_A4-balance_sheet.html, + old/sql-ledger/templates/Spanish_A4-check.tex, + old/sql-ledger/templates/Spanish_A4-income_statement.html, + old/sql-ledger/templates/Spanish_A4-invoice.html, + old/sql-ledger/templates/Spanish_A4-invoice.tex, + old/sql-ledger/templates/Spanish_A4-packing_list.html, + old/sql-ledger/templates/Spanish_A4-packing_list.tex, + old/sql-ledger/templates/Spanish_A4-purchase_order.html, + old/sql-ledger/templates/Spanish_A4-purchase_order.tex, + old/sql-ledger/templates/Spanish_A4-receipt.tex, + old/sql-ledger/templates/Spanish_A4-sales_order.html, + old/sql-ledger/templates/Spanish_A4-sales_order.tex, + old/sql-ledger/templates/Spanish_A4-statement.html, + old/sql-ledger/templates/Spanish_A4-statement.tex, + old/sql-ledger/templates/Spanish_Letter-balance_sheet.html, + old/sql-ledger/templates/Spanish_Letter-check.tex, + old/sql-ledger/templates/Spanish_Letter-income_statement.html, + old/sql-ledger/templates/Spanish_Letter-invoice.html, + old/sql-ledger/templates/Spanish_Letter-invoice.tex, + old/sql-ledger/templates/Spanish_Letter-packing_list.html, + old/sql-ledger/templates/Spanish_Letter-packing_list.tex, + old/sql-ledger/templates/Spanish_Letter-purchase_order.html, + old/sql-ledger/templates/Spanish_Letter-purchase_order.tex, + old/sql-ledger/templates/Spanish_Letter-receipt.tex, + old/sql-ledger/templates/Spanish_Letter-sales_order.html, + old/sql-ledger/templates/Spanish_Letter-sales_order.tex, + old/sql-ledger/templates/Spanish_Letter-statement.html, + old/sql-ledger/templates/Spanish_Letter-statement.tex, + old/sql-ledger/users/members.default: removing files from import + mistake + 2004-11-16 06:19 ivan * htetc/handler.pl: can't set $p without $cgi @@ -19422,6 +20938,2323 @@ * htetc/handler.pl: handle RT NoAuth sections +2004-11-15 02:35 ivan + + * sql-ledger/locale/: sv/arap, sv/cp, sv/oe, sv/pe, sv/pos, sv/rc, + nb/admin, sv/arapprn, sv/bp, sv/hr, sv/ps, sv/pw, nb/all, nb/am, + nb/ap, nb/ar, nb/ca, nb/ct, nb/gl, nb/ic, nb/ir, nb/io, nb/is, + nb/login, nb/menu, nb/rp, nb/COPYING, nb/LANGUAGE, nb/arap, + nb/oe, nb/arapprn, nb/bp, nb/cp, nb/hr, nb/pe, nb/pos, nb/ps, + nb/pw, nb/rc, tw_utf/admin, tw_utf/all, tw_utf/COPYING, + tw_utf/am, tw_utf/ap, tw_utf/ar, tw_utf/arap, tw_utf/bp, + tw_utf/ca, tw_utf/cp, tw_utf/ct, tw_utf/gl, tw_utf/hr, tw_utf/ic, + tw_utf/LANGUAGE, tw_utf/io, tw_utf/ir, tw_utf/is, tw_utf/login, + tw_utf/menu, tw_utf/oe, tw_utf/pe, tw_utf/pos, tw_big5/admin, + tw_utf/arapprn, tw_utf/ps, tw_utf/pw, tw_utf/rc, tw_utf/rp, + tw_big5/all, tw_big5/am, tw_big5/ap, tw_big5/COPYING, tw_big5/ar, + tw_big5/arap, tw_big5/bp, tw_big5/ca, tw_big5/cp, tw_big5/ct, + tw_big5/gl, tw_big5/hr, tw_big5/ic, tw_big5/io, tw_big5/ir, + tw_big5/LANGUAGE, tw_big5/is, tw_big5/login, tw_big5/menu, + tw_big5/oe, tw_big5/pe, be_nl/admin, tw_big5/arapprn, + tw_big5/pos, tw_big5/ps, tw_big5/pw, tw_big5/rc, tw_big5/rp, + tw_big5/temp, be_nl/all, be_nl/am, be_nl/ap, be_nl/ar, be_nl/ca, + be_nl/ct, be_nl/gl, be_nl/ic, be_nl/io, be_nl/ir, be_nl/is, + be_nl/login, be_nl/menu, be_nl/COPYING, be_nl/LANGUAGE, + be_nl/arap, be_nl/oe, be_nl/rp, be_nl/Num2text, be_nl/bp, + be_nl/cp, be_nl/pe, be_nl/pos, be_nl/rc, be_nl/arapprn, be_nl/hr, + be_nl/ps, be_nl/pw, cn_utf/admin, cn_utf/all, cn_utf/COPYING, + cn_utf/am, cn_utf/ap, cn_utf/ar, cn_utf/arap, cn_utf/bp, + cn_utf/ca, cn_utf/cp, cn_utf/ct, cn_utf/gl, cn_utf/hr, cn_utf/ic, + cn_utf/io, cn_utf/ir, cn_utf/LANGUAGE, cn_utf/is, cn_utf/login, + cn_utf/menu, cn_utf/oe, cn_utf/pe, cn_utf/pos, cn_utf/ps, + cn_utf/rc, cn_utf/arapprn, cn_utf/pw, cn_utf/rp, gr/COPYING, + gr/LANGUAGE, gr/admin, gr/all, gr/am, gr/ap, gr/ar, gr/ca, gr/ct, + gr/gl, gr/ic, gr/io, gr/ir, gr/is, gr/login, gr/menu, gr/rp, + gr/arap, gr/bp, gr/cp, gr/oe, gr/pe, gr/pos, gr/rc, gr/arapprn, + gr/hr, gr/ps, gr/pw: Initial revision + +2004-11-15 02:32 ivan + + * sql-ledger/locale/: co/admin, co/all, co/am, co/ap, co/ar, co/ca, + co/ct, co/gl, co/ic, co/io, co/ir, co/login, co/menu, co/rp, + co/arap, co/cp, co/is, co/oe, co/pe, co/bp, co/pos, co/ps, co/rc, + co/arapprn, co/hr, co/pw, dk/bp, dk/pos, dk/ps, dk/hr, + dk/arapprn, dk/pw, br/bp, br/arapprn, br/hr, br/pos, br/ps, + br/pw, it/arapprn, it/bp, it/hr, it/pos, it/ps, it/pw, ct/bp, + ct/pos, ct/ps, ct/arapprn, ct/hr, ct/pw, ee/Num2text, ee/bp, + ee/pos, ee/arapprn, ee/hr, ee/ps, ee/pw, nl/bp, nl/pos, + nl/arapprn, nl/hr, nl/ps, nl/pw, tr/bp, tr/arapprn, tr/hr, + tr/pos, tr/ps, tr/pw, ve/bp, ve/hr, ve/pos, ve/ps, ve/pw, + ve/arapprn, pa/bp, pa/hr, pa/pos, pa/ps, pa/pw, pa/arapprn, + cz/bp, cz/pos, cz/arapprn, cz/hr, cz/ps, cz/pw, pt/bp, pt/pos, + pt/ps, ec/admin, pt/arapprn, pt/hr, pt/pw, ec/all, ec/am, ec/ap, + ec/ar, ec/arap, ec/COPYING, ec/bp, ec/ca, ec/cp, ec/ct, ec/gl, + ec/hr, ec/ic, ec/io, ec/ir, ec/LANGUAGE, ec/Num2text, ec/is, + ec/login, ec/menu, ec/oe, ec/pe, ec/pos, ec/ps, ec/rc, + ec/arapprn, ec/pw, ec/rp, pl/arapprn, pl/bp, pl/hr, pl/pos, + pl/ps, pl/pw, mx/bp, mx/pos, mx/arapprn, mx/hr, mx/ps, mx/pw, + fi/bp, fi/pos, fi/arapprn, fi/hr, fi/ps, fi/pw, ru/bp, ru/pos, + ru/arapprn, ru/hr, ru/ps, ru/pw, ua/bp, ua/arapprn, ua/hr, + ua/pos, ua/ps, ua/pw, se/arapprn, se/bp, se/hr, se/pos, se/ps, + se/pw, hu/Num2text, hu/bp, hu/hr, hu/pos, hu/ps, hu/pw, + hu/arapprn, lt/arapprn, lt/bp, lt/hr, lt/pos, lt/ps, lt/pw, + is/bp, es_iso/login, is/arapprn, is/hr, is/pos, is/ps, is/pw, + es_iso/admin, es_iso/all, es_iso/ar, es_iso/ct, es_iso/gl, + es_iso/ic, es_iso/ir, es_iso/is, es_iso/rp, es_iso/am, es_iso/ap, + es_iso/ca, es_iso/menu, es_iso/COPYING, es_iso/LANGUAGE, + es_iso/Num2text, es_iso/arap, es_iso/io, es_iso/oe, es_iso/pe, + es_iso/bp, es_iso/cp, es_iso/pos, es_iso/rc, es_iso/arapprn, + es_iso/hr, es_iso/ps, es_iso/pw, lv/COPYING, lv/LANGUAGE, + lv/admin, lv/all, lv/am, lv/ap, lv/ar, lv/ca, lv/ct, lv/gl, + lv/ic, lv/io, lv/ir, lv/login, lv/menu, lv/rp, lv/arap, lv/cp, + lv/is, lv/oe, lv/pe, lv/bp, lv/pos, lv/ps, lv/rc, es_utf/admin, + es_utf/login, lv/arapprn, lv/hr, lv/pw, es_utf/all, es_utf/ar, + es_utf/ct, es_utf/gl, es_utf/ic, es_utf/ir, es_utf/is, es_utf/rp, + es_utf/LANGUAGE, es_utf/am, es_utf/ap, es_utf/ca, es_utf/io, + es_utf/menu, es_utf/COPYING, es_utf/Num2text, es_utf/arap, + es_utf/bp, es_utf/cp, es_utf/oe, es_utf/pe, es_utf/pos, + es_utf/rc, es_utf/arapprn, es_utf/hr, es_utf/ps, es_utf/pw, + eg/COPYING, eg/LANGUAGE, eg/admin, en_GB/arapprn, en_GB/hr, + en_GB/pos, en_GB/ps, en_GB/pw, eg/all, eg/am, eg/ap, eg/ar, + eg/arap, eg/bp, eg/ca, eg/cp, eg/ct, eg/gl, eg/ic, eg/io, eg/ir, + eg/hr, eg/is, eg/login, eg/menu, eg/oe, eg/arapprn, eg/pe, + eg/pos, eg/ps, eg/pw, eg/rc, eg/rp, sv/COPYING, sv/LANGUAGE, + sv/admin, sv/all, sv/am, sv/ap, sv/ar, sv/ca, sv/ct, sv/gl, + sv/ic, sv/io, sv/ir, sv/login, sv/is, sv/menu, sv/rp: Initial + revision + +2004-11-15 02:29 ivan + + * sql-ledger/: index.html, sql-ledger.gif, bin/mozilla/bp.pl, + bin/mozilla/pos.pl, bin/mozilla/ps.pl, bin/mozilla/hr.pl, + bin/js/menu.pl, bin/mozilla/arapprn.pl, bin/mozilla/pw.pl, + doc/COPYRIGHT, doc/README.DB2, doc/UPGRADE-2.0.8-2.0.9, + doc/UPGRADE-2.0.9-2.2.0, doc/UPGRADE-2.2.0-2.2.7, + doc/UPGRADE-2.2.7-2.4.0, doc/UPGRADE-2.4.0-2.4.1, + doc/UPGRADE-2.4.1-2.4.2, doc/UPGRADE-2.4.2-2.4.3, + doc/UPGRADE-2.4.3-2.4.4, sql/Italy-gifi.sql, + sql/Czech-Republic-chart.sql, + sql/Simplified-Chinese_Default-chart.sql, + sql/Traditional-Chinese_Default-chart.sql, + sql/Canada-English_General-chart.sql, + sql/Pg-upgrade-2.3.0-2.3.1.sql, sql/Swedish-chart.sql, + sql/DB2-create.sql, sql/Italy_General-chart.sql, + sql/Oracle-upgrade-2.0.8-2.2.0.sql, + sql/Pg-upgrade-2.0.8-2.2.0.sql, sql/Pg-upgrade-2.2.0-2.3.0.sql, + sql/Hungary-chart.sql, sql/Norwegian_Default-chart.sql, + sql/Belgium-chart.sql, sql/Belgium-gifi.sql, + sql/Hungary-gifi.sql, sql/Pg-upgrade-2.3.1-2.3.3.sql, + sql/Canada-English-gifi.sql, sql/Italy_cc2424-chart.sql, + sql/Pg-upgrade-2.3.3-2.3.4.sql, sql/Pg-upgrade-2.3.4-2.3.5.sql, + sql/Pg-upgrade-2.3.5-2.3.6.sql, sql/Spain-ISO-chart.sql, + sql/Spain-UTF8-chart.sql, sql/Canada-French-gifi.sql, + sql/DB2-indices.sql, sql/DB2-remove.sql, sql/DB2-set.sql, + sql/DB2-tables.sql, sql/DB2-sql-ledger.order, + sql/Latvia-chart.sql, sql/Pg-upgrade-2.3.6-2.3.7.sql, + sql/NAICS.sql, sql/Pg-upgrade-2.3.7-2.3.8.sql, + sql/Pg-upgrade-2.3.8-2.3.9.sql, sql/Colombia-PUC-chart.sql, + sql/Colombia-PUC-gifi.sql, sql/Egypt-chart.sql, + sql/Pg-functions.sql, sql/US_Manufacturing-chart.sql, + sql/Pg-upgrade-2.3.9-2.4.2.sql, sql/Pg-upgrade-2.4.2-2.4.3.sql, + sql/Pg-upgrade-2.4.3-2.4.4.sql, + sql/Simplified-Chinese_Default-UTF8-chart.sql, + sql/Traditional-Chinese_Default-UTF8-chart.sql, + sql/US_Service_Company-chart.sql, + templates/Default-pos_invoice.txt, + templates/Norwegian-balance_sheet.html, + templates/Danish-pos_invoice.txt, + templates/Dutch-pos_invoice.txt, templates/Norwegian-check.tex, + templates/Norwegian-income_statement.html, + templates/Norwegian-invoice.html, + templates/Norwegian-invoice.tex, + templates/Norwegian-packing_list.html, + templates/Norwegian-packing_list.tex, + templates/Norwegian-purchase_order.html, + templates/Norwegian-purchase_order.tex, + templates/Norwegian-receipt.tex, + templates/Italian-balance_sheet.html, + templates/Italian-check.tex, + templates/Italian-income_statement.html, + templates/Italian-invoice.html, templates/Italian-invoice.tex, + templates/Italian-packing_list.html, + templates/Italian-packing_list.tex, + templates/Norwegian-sales_order.html, + templates/Norwegian-sales_order.tex, + templates/Norwegian-statement.html, + templates/Norwegian-statement.tex, + templates/Default-bin_list.html, templates/Default-bin_list.tex, + templates/Hungarian-balance_sheet.html, + templates/Italian-purchase_order.html, + templates/Italian-purchase_order.tex, + templates/Italian-receipt.tex, + templates/Italian-sales_order.html, + templates/Italian-sales_order.tex, + templates/Italian-statement.html, + templates/Italian-statement.tex, + templates/Default-pick_list.html, + templates/Default-pick_list.tex, + templates/Default-request_quotation.html, + templates/Default-request_quotation.tex, + templates/Default-sales_quotation.html, + templates/Default-sales_quotation.tex, + templates/Hungarian-check.tex, + templates/Hungarian-income_statement.html, + templates/Hungarian-invoice.html, + templates/Hungarian-invoice.tex, + templates/Hungarian-packing_list.html, + templates/Hungarian-packing_list.tex, + templates/Hungarian-pos_invoice.txt, + templates/Hungarian-purchase_order.html, + templates/Hungarian-purchase_order.tex, + templates/Hungarian-receipt.tex, + templates/Default-work_order.tex, + templates/Hungarian-sales_order.html, + templates/Hungarian-sales_order.tex, + templates/Hungarian-statement.html, + templates/Hungarian-statement.tex, templates/Danish-bin_list.tex, + templates/Danish-work_order.html, + templates/Danish-work_order.tex, + templates/Default-work_order.html, + templates/Dutch-work_order.html, templates/Dutch-work_order.tex, + templates/Estonian-pos_invoice.txt, + templates/Estonian-work_order.html, + templates/Estonian-work_order.tex, + templates/French-pos_invoice.txt, + templates/French-work_order.html, + templates/French-work_order.tex, + templates/German-work_order.html, + templates/German-work_order.tex, + templates/Hungarian-work_order.html, + templates/Hungarian-work_order.tex, + templates/Italian-work_order.html, + templates/Italian-work_order.tex, + templates/Norwegian-work_order.html, + templates/Norwegian-work_order.tex, + templates/Service-work_order.html, + templates/Service-work_order.tex, + templates/Spanish_A4-work_order.html, + templates/Brazilian_Portuguese-bin_list.html, + templates/Brazilian_Portuguese-bin_list.tex, + templates/Danish-pick_list.html, + templates/German-pos_invoice.txt, + templates/Italian-pos_invoice.txt, + templates/Norwegian-pos_invoice.txt, + templates/Service-pos_invoice.txt, + templates/Spanish_A4-pos_invoice.txt, + templates/Spanish_A4-work_order.tex, + templates/Spanish_Letter-pos_invoice.txt, + templates/Spanish_Letter-work_order.html, + templates/Spanish_Letter-work_order.tex, + templates/Brazilian_Portuguese-pick_list.html, + templates/Brazilian_Portuguese-pick_list.tex, + templates/Brazilian_Portuguese-pos_invoice.txt, + templates/Brazilian_Portuguese-request_quotation.html, + templates/Brazilian_Portuguese-request_quotation.tex, + templates/Brazilian_Portuguese-sales_quotation.html, + templates/Brazilian_Portuguese-sales_quotation.tex, + templates/Brazilian_Portuguese-work_order.html, + templates/Brazilian_Portuguese-work_order.tex, + templates/Danish-bin_list.html, templates/Danish-pick_list.tex, + templates/Danish-request_quotation.html, + templates/Danish-request_quotation.tex, + templates/Danish-sales_quotation.html, + templates/Danish-sales_quotation.tex, + templates/Dutch-bin_list.html, templates/Dutch-bin_list.tex, + templates/Dutch-pick_list.html, templates/Dutch-pick_list.tex, + templates/Dutch-request_quotation.html, + templates/Dutch-request_quotation.tex, + templates/Dutch-sales_quotation.html, + templates/Dutch-sales_quotation.tex, + templates/Estonian-bin_list.html, + templates/Estonian-bin_list.tex, + templates/Estonian-pick_list.html, + templates/Estonian-pick_list.tex, + templates/Estonian-request_quotation.html, + templates/Estonian-request_quotation.tex, + templates/French-bin_list.html, templates/French-bin_list.tex, + templates/French-pick_list.html, templates/French-pick_list.tex, + templates/French-request_quotation.html, + templates/French-request_quotation.tex, + templates/French-sales_quotation.html, + templates/French-sales_quotation.tex, + templates/German-bin_list.html, templates/German-bin_list.tex, + templates/German-pick_list.html, templates/German-pick_list.tex, + templates/German-request_quotation.html, + templates/German-request_quotation.tex, + templates/German-sales_quotation.html, + templates/German-sales_quotation.tex, + templates/Hungarian-bin_list.html, + templates/Hungarian-bin_list.tex, + templates/Hungarian-pick_list.html, + templates/Hungarian-pick_list.tex, + templates/Hungarian-request_quotation.html, + templates/Hungarian-request_quotation.tex, + templates/Hungarian-sales_quotation.html, + templates/Hungarian-sales_quotation.tex, + templates/Italian-bin_list.html, templates/Italian-bin_list.tex, + templates/Italian-pick_list.html, + templates/Italian-pick_list.tex, + templates/Italian-request_quotation.html, + templates/Italian-request_quotation.tex, + templates/Italian-sales_quotation.html, + templates/Italian-sales_quotation.tex, + templates/Norwegian-bin_list.html, + templates/Norwegian-bin_list.tex, + templates/Norwegian-pick_list.html, + templates/Norwegian-pick_list.tex, + templates/Norwegian-request_quotation.html, + templates/Norwegian-request_quotation.tex, + templates/Norwegian-sales_quotation.html, + templates/Norwegian-sales_quotation.tex, + templates/Service-bin_list.html, templates/Service-bin_list.tex, + templates/Service-pick_list.html, + templates/Service-pick_list.tex, + templates/Service-request_quotation.html, + templates/Service-request_quotation.tex, + templates/Service-sales_quotation.html, + templates/Service-sales_quotation.tex, + templates/Spanish_A4-bin_list.html, + templates/Spanish_A4-bin_list.tex, + templates/Spanish_A4-pick_list.html, + templates/Spanish_A4-pick_list.tex, + templates/Spanish_A4-request_quotation.html, + templates/Spanish_A4-request_quotation.tex, + templates/Spanish_A4-sales_quotation.html, + templates/Spanish_A4-sales_quotation.tex, + templates/Spanish_Letter-bin_list.html, + templates/Spanish_Letter-bin_list.tex, + templates/Brazilian_Portuguese-ap_transaction.html, + templates/Brazilian_Portuguese-ap_transaction.tex, + templates/Brazilian_Portuguese-ar_transaction.html, + templates/Spanish_Letter-pick_list.html, + templates/Spanish_Letter-pick_list.tex, + templates/Spanish_Letter-request_quotation.html, + templates/Spanish_Letter-request_quotation.tex, + templates/Spanish_Letter-sales_quotation.html, + templates/Spanish_Letter-sales_quotation.tex, + templates/Brazilian_Portuguese-ar_transaction.tex, + templates/Danish-ap_transaction.html, + templates/Danish-ap_transaction.tex, + templates/Danish-ar_transaction.html, + templates/Danish-ar_transaction.tex, + templates/Default-ap_transaction.html, + templates/Default-ap_transaction.tex, + templates/Default-ar_transaction.html, + templates/Default-ar_transaction.tex, + templates/Dutch-ap_transaction.html, + templates/Dutch-ap_transaction.tex, + templates/Dutch-ar_transaction.html, + templates/Dutch-ar_transaction.tex, + templates/Estonian-ap_transaction.html, + templates/Estonian-ap_transaction.tex, + templates/Estonian-ar_transaction.html, + templates/Estonian-ar_transaction.tex, + templates/French-ap_transaction.html, + templates/French-ap_transaction.tex, + templates/French-ar_transaction.html, + templates/French-ar_transaction.tex, + templates/German-ap_transaction.html, + templates/German-ap_transaction.tex, + templates/German-ar_transaction.html, + templates/German-ar_transaction.tex, + templates/Hungarian-ap_transaction.html, + templates/Hungarian-ap_transaction.tex, + templates/Hungarian-ar_transaction.html, + templates/Hungarian-ar_transaction.tex, + templates/Italian-ap_transaction.html, + templates/Italian-ap_transaction.tex, + templates/Italian-ar_transaction.html, + templates/Italian-ar_transaction.tex, + templates/Norwegian-ap_transaction.html, + templates/Norwegian-ap_transaction.tex, + templates/Norwegian-ar_transaction.html, + templates/Norwegian-ar_transaction.tex, + templates/Service-ap_transaction.html, + templates/Service-ap_transaction.tex, + templates/Service-ar_transaction.html, + templates/Service-ar_transaction.tex, + templates/Spanish_A4-ap_transaction.html, + templates/Spanish_A4-ap_transaction.tex, + templates/Spanish_A4-ar_transaction.html, + templates/Spanish_A4-ar_transaction.tex, + templates/Spanish_Letter-ap_transaction.html, + templates/Spanish_Letter-ap_transaction.tex, + templates/Spanish_Letter-ar_transaction.html, + templates/Spanish_Letter-ar_transaction.tex, + users/sql-ledger.eps, users/sql-ledger.png, SL/BP.pm, SL/HR.pm, + SL/OP.pm, locale/de/bp, locale/de/hr, locale/de/pos, + locale/de/ps, locale/de/arapprn, locale/de/pw, locale/fr/bp, + locale/fr/pos, locale/fr/hr, locale/fr/ps, locale/co/COPYING, + locale/co/LANGUAGE, locale/co/Num2text, locale/fr/Num2text, + locale/fr/arapprn, locale/fr/pw: Initial revision + +2004-11-15 02:28 ivan + + * sql-ledger/sql-ledger/: VERSION, am.pl, favicon.ico, index.html, + login.pl, menu.ini, setup.pl, sql-ledger.conf.default, + sql-ledger.gif, sql-ledger.png, SL/AM.pm, SL/AP.pm, SL/AR.pm, + SL/BP.pm, SL/CA.pm, SL/CP.pm, SL/CT.pm, SL/Form.pm, SL/GL.pm, + SL/HR.pm, SL/IC.pm, SL/IR.pm, SL/IS.pm, SL/Inifile.pm, + SL/Mailer.pm, SL/Menu.pm, SL/Num2text.pm, SL/OE.pm, SL/OP.pm, + SL/PE.pm, SL/RC.pm, SL/RP.pm, SL/User.pm, bin/js/menu.pl, + bin/lynx/menu.pl, bin/mozilla/admin.pl, bin/mozilla/am.pl, + bin/mozilla/ap.pl, bin/mozilla/ar.pl, bin/mozilla/arap.pl, + bin/mozilla/arapprn.pl, bin/mozilla/bp.pl, bin/mozilla/ca.pl, + bin/mozilla/cp.pl, bin/mozilla/ct.pl, bin/mozilla/gl.pl, + bin/mozilla/hr.pl, bin/mozilla/ic.pl, bin/mozilla/io.pl, + bin/mozilla/ir.pl, bin/mozilla/is.pl, bin/mozilla/login.pl, + bin/mozilla/menu.pl, bin/mozilla/oe.pl, bin/mozilla/pe.pl, + bin/mozilla/pos.pl, bin/mozilla/ps.pl, bin/mozilla/pw.pl, + bin/mozilla/rc.pl, bin/mozilla/rp.pl, css/sql-ledger.css, + doc/COPYING, doc/COPYRIGHT, doc/README, doc/README.DB2, + doc/UPGRADE-1.6-1.8, doc/UPGRADE-1.8-1.8.3, + doc/UPGRADE-1.8.3-1.8.4, doc/UPGRADE-1.8.4-1.8.5, + doc/UPGRADE-1.8.5-1.8.7, doc/UPGRADE-1.8.7-2.0.0, + doc/UPGRADE-2.0-2.0.8, doc/UPGRADE-2.0.8-2.0.9, + doc/UPGRADE-2.0.9-2.2.0, doc/UPGRADE-2.2.0-2.2.7, + doc/UPGRADE-2.2.7-2.4.0, doc/UPGRADE-2.4.0-2.4.1, + doc/UPGRADE-2.4.1-2.4.2, doc/UPGRADE-2.4.2-2.4.3, + doc/UPGRADE-2.4.3-2.4.4, doc/faq.html, locale/be_nl/COPYING, + locale/be_nl/LANGUAGE, locale/be_nl/Num2text, locale/be_nl/admin, + locale/be_nl/all, locale/be_nl/am, locale/be_nl/ap, + locale/be_nl/ar, locale/be_nl/arap, locale/be_nl/arapprn, + locale/be_nl/bp, locale/be_nl/ca, locale/be_nl/cp, + locale/be_nl/ct, locale/be_nl/gl, locale/be_nl/hr, + locale/be_nl/ic, locale/be_nl/io, locale/be_nl/ir, + locale/be_nl/is, locale/be_nl/login, locale/be_nl/menu, + locale/be_nl/oe, locale/be_nl/pe, locale/be_nl/pos, + locale/be_nl/ps, locale/be_nl/pw, locale/be_nl/rc, + locale/be_nl/rp, locale/br/COPYING, locale/br/LANGUAGE, + locale/br/admin, locale/br/all, locale/br/am, locale/br/ap, + locale/br/ar, locale/br/arap, locale/br/arapprn, locale/br/bp, + locale/br/ca, locale/br/cp, locale/br/ct, locale/br/gl, + locale/br/hr, locale/br/ic, locale/br/io, locale/br/ir, + locale/br/is, locale/br/login, locale/br/menu, locale/br/oe, + locale/br/pe, locale/br/pos, locale/br/ps, locale/br/pw, + locale/br/rc, locale/br/rp, locale/cn_utf/COPYING, + locale/cn_utf/LANGUAGE, locale/cn_utf/admin, locale/cn_utf/all, + locale/cn_utf/am, locale/cn_utf/ap, locale/cn_utf/ar, + locale/cn_utf/arap, locale/cn_utf/arapprn, locale/cn_utf/bp, + locale/cn_utf/ca, locale/cn_utf/cp, locale/cn_utf/ct, + locale/cn_utf/gl, locale/cn_utf/hr, locale/cn_utf/ic, + locale/cn_utf/io, locale/cn_utf/ir, locale/cn_utf/is, + locale/cn_utf/login, locale/cn_utf/menu, locale/cn_utf/oe, + locale/cn_utf/pe, locale/cn_utf/pos, locale/cn_utf/ps, + locale/cn_utf/pw, locale/cn_utf/rc, locale/cn_utf/rp, + locale/co/COPYING, locale/co/LANGUAGE, locale/co/Num2text, + locale/co/admin, locale/co/all, locale/co/am, locale/co/ap, + locale/co/ar, locale/co/arap, locale/co/arapprn, locale/co/bp, + locale/co/ca, locale/co/cp, locale/co/ct, locale/co/gl, + locale/co/hr, locale/co/ic, locale/co/io, locale/co/ir, + locale/co/is, locale/co/login, locale/co/menu, locale/co/oe, + locale/co/pe, locale/co/pos, locale/co/ps, locale/co/pw, + locale/co/rc, locale/co/rp, locale/ct/COPYING, + locale/ct/LANGUAGE, locale/ct/admin, locale/ct/all, locale/ct/am, + locale/ct/ap, locale/ct/ar, locale/ct/arap, locale/ct/arapprn, + locale/ct/bp, locale/ct/ca, locale/ct/cp, locale/ct/ct, + locale/ct/gl, locale/ct/hr, locale/ct/ic, locale/ct/io, + locale/ct/ir, locale/ct/is, locale/ct/login, locale/ct/menu, + locale/ct/oe, locale/ct/pe, locale/ct/pos, locale/ct/ps, + locale/ct/pw, locale/ct/rc, locale/ct/rp, locale/cz/COPYING, + locale/cz/LANGUAGE, locale/cz/admin, locale/cz/all, locale/cz/am, + locale/cz/ap, locale/cz/ar, locale/cz/arap, locale/cz/arapprn, + locale/cz/bp, locale/cz/ca, locale/cz/cp, locale/cz/ct, + locale/cz/gl, locale/cz/hr, locale/cz/ic, locale/cz/io, + locale/cz/ir, locale/cz/is, locale/cz/login, locale/cz/menu, + locale/cz/oe, locale/cz/pe, locale/cz/pos, locale/cz/ps, + locale/cz/pw, locale/cz/rc, locale/cz/rp, locale/de/COPYING, + locale/de/LANGUAGE, locale/de/Num2text, locale/de/admin, + locale/de/am, locale/de/ap, locale/de/ar, locale/de/arap, + locale/de/arapprn, locale/de/bp, locale/de/ca, locale/de/cp, + locale/de/ct, locale/de/gl, locale/de/hr, locale/de/ic, + locale/de/io, locale/de/ir, locale/de/is, locale/de/locales.pl, + locale/de/login, locale/de/menu, locale/de/oe, locale/de/pe, + locale/de/pos, locale/de/ps, locale/de/pw, locale/de/rc, + locale/de/rp, locale/dk/COPYING, locale/dk/LANGUAGE, + locale/dk/admin, locale/dk/all, locale/dk/am, locale/dk/ap, + locale/dk/ar, locale/dk/arap, locale/dk/arapprn, locale/dk/bp, + locale/dk/ca, locale/dk/cp, locale/dk/ct, locale/dk/gl, + locale/dk/hr, locale/dk/ic, locale/dk/io, locale/dk/ir, + locale/dk/is, locale/dk/login, locale/dk/menu, locale/dk/oe, + locale/dk/pe, locale/dk/pos, locale/dk/ps, locale/dk/pw, + locale/dk/rc, locale/dk/rp, locale/ec/COPYING, + locale/ec/LANGUAGE, locale/ec/Num2text, locale/ec/admin, + locale/ec/all, locale/ec/am, locale/ec/ap, locale/ec/ar, + locale/ec/arap, locale/ec/arapprn, locale/ec/bp, locale/ec/ca, + locale/ec/cp, locale/ec/ct, locale/ec/gl, locale/ec/hr, + locale/ec/ic, locale/ec/io, locale/ec/ir, locale/ec/is, + locale/ec/login, locale/ec/menu, locale/ec/oe, locale/ec/pe, + locale/ec/pos, locale/ec/ps, locale/ec/pw, locale/ec/rc, + locale/ec/rp, locale/ee/COPYING, locale/ee/LANGUAGE, + locale/ee/Num2text, locale/ee/admin, locale/ee/all, locale/ee/am, + locale/ee/ap, locale/ee/ar, locale/ee/arap, locale/ee/arapprn, + locale/ee/bp, locale/ee/ca, locale/ee/cp, locale/ee/ct, + locale/ee/gl, locale/ee/hr, locale/ee/ic, locale/ee/io, + locale/ee/ir, locale/ee/is, locale/ee/login, locale/ee/menu, + locale/ee/oe, locale/ee/pe, locale/ee/pos, locale/ee/ps, + locale/ee/pw, locale/ee/rc, locale/ee/rp, locale/eg/COPYING, + locale/eg/LANGUAGE, locale/eg/admin, locale/eg/all, locale/eg/am, + locale/eg/ap, locale/eg/ar, locale/eg/arap, locale/eg/arapprn, + locale/eg/bp, locale/eg/ca, locale/eg/cp, locale/eg/ct, + locale/eg/gl, locale/eg/hr, locale/eg/ic, locale/eg/io, + locale/eg/ir, locale/eg/is, locale/eg/login, locale/eg/menu, + locale/eg/oe, locale/eg/pe, locale/eg/pos, locale/eg/ps, + locale/eg/pw, locale/eg/rc, locale/eg/rp, locale/en_GB/COPYING, + locale/en_GB/LANGUAGE, locale/en_GB/admin, locale/en_GB/all, + locale/en_GB/am, locale/en_GB/ap, locale/en_GB/ar, + locale/en_GB/arap, locale/en_GB/arapprn, locale/en_GB/bp, + locale/en_GB/ca, locale/en_GB/cp, locale/en_GB/ct, + locale/en_GB/gl, locale/en_GB/hr, locale/en_GB/ic, + locale/en_GB/io, locale/en_GB/ir, locale/en_GB/is, + locale/en_GB/login, locale/en_GB/menu, locale/en_GB/oe, + locale/en_GB/pe, locale/en_GB/pos, locale/en_GB/ps, + locale/en_GB/pw, locale/en_GB/rc, locale/en_GB/rp, + locale/es_iso/COPYING, locale/es_iso/LANGUAGE, + locale/es_iso/Num2text, locale/es_iso/admin, locale/es_iso/all, + locale/es_iso/am, locale/es_iso/ap, locale/es_iso/ar, + locale/es_iso/arap, locale/es_iso/arapprn, locale/es_iso/bp, + locale/es_iso/ca, locale/es_iso/cp, locale/es_iso/ct, + locale/es_iso/gl, locale/es_iso/hr, locale/es_iso/ic, + locale/es_iso/io, locale/es_iso/ir, locale/es_iso/is, + locale/es_iso/login, locale/es_iso/menu, locale/es_iso/oe, + locale/es_iso/pe, locale/es_iso/pos, locale/es_iso/ps, + locale/es_iso/pw, locale/es_iso/rc, locale/es_iso/rp, + locale/es_utf/COPYING, locale/es_utf/LANGUAGE, + locale/es_utf/Num2text, locale/es_utf/admin, locale/es_utf/all, + locale/es_utf/am, locale/es_utf/ap, locale/es_utf/ar, + locale/es_utf/arap, locale/es_utf/arapprn, locale/es_utf/bp, + locale/es_utf/ca, locale/es_utf/cp, locale/es_utf/ct, + locale/es_utf/gl, locale/es_utf/hr, locale/es_utf/ic, + locale/es_utf/io, locale/es_utf/ir, locale/es_utf/is, + locale/es_utf/login, locale/es_utf/menu, locale/es_utf/oe, + locale/es_utf/pe, locale/es_utf/pos, locale/es_utf/ps, + locale/es_utf/pw, locale/es_utf/rc, locale/es_utf/rp, + locale/fi/COPYING, locale/fi/LANGUAGE, locale/fi/admin, + locale/fi/all, locale/fi/am, locale/fi/ap, locale/fi/ar, + locale/fi/arap, locale/fi/arapprn, locale/fi/bp, locale/fi/ca, + locale/fi/cp, locale/fi/ct, locale/fi/gl, locale/fi/hr, + locale/fi/ic, locale/fi/io, locale/fi/ir, locale/fi/is, + locale/fi/login, locale/fi/menu, locale/fi/oe, locale/fi/pe, + locale/fi/pos, locale/fi/ps, locale/fi/pw, locale/fi/rc, + locale/fi/rp, locale/fr/COPYING, locale/fr/LANGUAGE, + locale/fr/Num2text, locale/fr/admin, locale/fr/all, locale/fr/am, + locale/fr/ap, locale/fr/ar, locale/fr/arap, locale/fr/arapprn, + locale/fr/bp, locale/fr/ca, locale/fr/cp, locale/fr/ct, + locale/fr/gl, locale/fr/hr, locale/fr/ic, locale/fr/io, + locale/fr/ir, locale/fr/is, locale/fr/login, locale/fr/menu, + locale/fr/oe, locale/fr/pe, locale/fr/pos, locale/fr/ps, + locale/fr/pw, locale/fr/rc, locale/fr/rp, locale/gr/COPYING, + locale/gr/LANGUAGE, locale/gr/admin, locale/gr/all, locale/gr/am, + locale/gr/ap, locale/gr/ar, locale/gr/arap, locale/gr/arapprn, + locale/gr/bp, locale/gr/ca, locale/gr/cp, locale/gr/ct, + locale/gr/gl, locale/gr/hr, locale/gr/ic, locale/gr/io, + locale/gr/ir, locale/gr/is, locale/gr/login, locale/gr/menu, + locale/gr/oe, locale/gr/pe, locale/gr/pos, locale/gr/ps, + locale/gr/pw, locale/gr/rc, locale/gr/rp, locale/hu/COPYING, + locale/hu/LANGUAGE, locale/hu/Num2text, locale/hu/admin, + locale/hu/all, locale/hu/am, locale/hu/ap, locale/hu/ar, + locale/hu/arap, locale/hu/arapprn, locale/hu/bp, locale/hu/ca, + locale/hu/cp, locale/hu/ct, locale/hu/gl, locale/hu/hr, + locale/hu/ic, locale/hu/io, locale/hu/ir, locale/hu/is, + locale/hu/login, locale/hu/menu, locale/hu/oe, locale/hu/pe, + locale/hu/pos, locale/hu/ps, locale/hu/pw, locale/hu/rc, + locale/hu/rp, locale/is/COPYING, locale/is/LANGUAGE, + locale/is/admin, locale/is/all, locale/is/am, locale/is/ap, + locale/is/ar, locale/is/arap, locale/is/arapprn, locale/is/bp, + locale/is/ca, locale/is/cp, locale/is/ct, locale/is/gl, + locale/is/hr, locale/is/ic, locale/is/io, locale/is/ir, + locale/is/is, locale/is/login, locale/is/menu, locale/is/oe, + locale/is/pe, locale/is/pos, locale/is/ps, locale/is/pw, + locale/is/rc, locale/is/rp, locale/it/COPYING, + locale/it/LANGUAGE, locale/it/Num2text, locale/it/admin, + locale/it/all, locale/it/am, locale/it/ap, locale/it/ar, + locale/it/arap, locale/it/arapprn, locale/it/bp, locale/it/ca, + locale/it/cp, locale/it/ct, locale/it/gl, locale/it/hr, + locale/it/ic, locale/it/io, locale/it/ir, locale/it/is, + locale/it/login, locale/it/menu, locale/it/oe, locale/it/pe, + locale/it/pos, locale/it/ps, locale/it/pw, locale/it/qe, + locale/it/rc, locale/it/rp, locale/lt/COPYING, + locale/lt/LANGUAGE, locale/lt/admin, locale/lt/all, locale/lt/am, + locale/lt/ap, locale/lt/ar, locale/lt/arap, locale/lt/arapprn, + locale/lt/bp, locale/lt/ca, locale/lt/cp, locale/lt/ct, + locale/lt/gl, locale/lt/hr, locale/lt/ic, locale/lt/io, + locale/lt/ir, locale/lt/is, locale/lt/login, locale/lt/menu, + locale/lt/oe, locale/lt/pe, locale/lt/pos, locale/lt/ps, + locale/lt/pw, locale/lt/rc, locale/lt/rp, locale/lv/COPYING, + locale/lv/LANGUAGE, locale/lv/admin, locale/lv/all, locale/lv/am, + locale/lv/ap, locale/lv/ar, locale/lv/arap, locale/lv/arapprn, + locale/lv/bp, locale/lv/ca, locale/lv/cp, locale/lv/ct, + locale/lv/gl, locale/lv/hr, locale/lv/ic, locale/lv/io, + locale/lv/ir, locale/lv/is, locale/lv/login, locale/lv/menu, + locale/lv/oe, locale/lv/pe, locale/lv/pos, locale/lv/ps, + locale/lv/pw, locale/lv/rc, locale/lv/rp, locale/mx/COPYING, + locale/mx/LANGUAGE, locale/mx/admin, locale/mx/all, locale/mx/am, + locale/mx/ap, locale/mx/ar, locale/mx/arap, locale/mx/arapprn, + locale/mx/bp, locale/mx/ca, locale/mx/cp, locale/mx/ct, + locale/mx/gl, locale/mx/hr, locale/mx/ic, locale/mx/io, + locale/mx/ir, locale/mx/is, locale/mx/login, locale/mx/menu, + locale/mx/oe, locale/mx/pe, locale/mx/pos, locale/mx/ps, + locale/mx/pw, locale/mx/rc, locale/mx/rp, locale/nb/COPYING, + locale/nb/LANGUAGE, locale/nb/admin, locale/nb/all, locale/nb/am, + locale/nb/ap, locale/nb/ar, locale/nb/arap, locale/nb/arapprn, + locale/nb/bp, locale/nb/ca, locale/nb/cp, locale/nb/ct, + locale/nb/gl, locale/nb/hr, locale/nb/ic, locale/nb/io, + locale/nb/ir, locale/nb/is, locale/nb/login, locale/nb/menu, + locale/nb/oe, locale/nb/pe, locale/nb/pos, locale/nb/ps, + locale/nb/pw, locale/nb/rc, locale/nb/rp, locale/nl/COPYING, + locale/nl/LANGUAGE, locale/nl/Num2text, locale/nl/admin, + locale/nl/all, locale/nl/am, locale/nl/ap, locale/nl/ar, + locale/nl/arap, locale/nl/arapprn, locale/nl/bp, locale/nl/ca, + locale/nl/cp, locale/nl/ct, locale/nl/gl, locale/nl/hr, + locale/nl/ic, locale/nl/io, locale/nl/ir, locale/nl/is, + locale/nl/login, locale/nl/menu, locale/nl/oe, locale/nl/pe, + locale/nl/pos, locale/nl/ps, locale/nl/pw, locale/nl/rc, + locale/nl/rp, locale/pa/COPYING, locale/pa/LANGUAGE, + locale/pa/admin, locale/pa/all, locale/pa/am, locale/pa/ap, + locale/pa/ar, locale/pa/arap, locale/pa/arapprn, locale/pa/bp, + locale/pa/ca, locale/pa/cp, locale/pa/ct, locale/pa/gl, + locale/pa/hr, locale/pa/ic, locale/pa/io, locale/pa/ir, + locale/pa/is, locale/pa/login, locale/pa/menu, locale/pa/oe, + locale/pa/pe, locale/pa/pos, locale/pa/ps, locale/pa/pw, + locale/pa/rc, locale/pa/rp, locale/pl/COPYING, + locale/pl/LANGUAGE, locale/pl/admin, locale/pl/all, locale/pl/am, + locale/pl/ap, locale/pl/ar, locale/pl/arap, locale/pl/arapprn, + locale/pl/bp, locale/pl/ca, locale/pl/cp, locale/pl/ct, + locale/pl/gl, locale/pl/hr, locale/pl/ic, locale/pl/io, + locale/pl/ir, locale/pl/is, locale/pl/login, locale/pl/menu, + locale/pl/oe, locale/pl/pe, locale/pl/pos, locale/pl/ps, + locale/pl/pw, locale/pl/rc, locale/pl/rp, locale/pt/COPYING, + locale/pt/LANGUAGE, locale/pt/admin, locale/pt/all, locale/pt/am, + locale/pt/ap, locale/pt/ar, locale/pt/arap, locale/pt/arapprn, + locale/pt/bp, locale/pt/ca, locale/pt/cp, locale/pt/ct, + locale/pt/gl, locale/pt/hr, locale/pt/ic, locale/pt/io, + locale/pt/ir, locale/pt/is, locale/pt/login, locale/pt/menu, + locale/pt/oe, locale/pt/pe, locale/pt/pos, locale/pt/ps, + locale/pt/pw, locale/pt/rc, locale/pt/rp, locale/ru/COPYING, + locale/ru/LANGUAGE, locale/ru/admin, locale/ru/all, locale/ru/am, + locale/ru/ap, locale/ru/ar, locale/ru/arap, locale/ru/arapprn, + locale/ru/bp, locale/ru/ca, locale/ru/cp, locale/ru/ct, + locale/ru/gl, locale/ru/hr, locale/ru/ic, locale/ru/io, + locale/ru/ir, locale/ru/is, locale/ru/login, locale/ru/menu, + locale/ru/oe, locale/ru/pe, locale/ru/pos, locale/ru/ps, + locale/ru/pw, locale/ru/rc, locale/ru/rp, locale/se/COPYING, + locale/se/LANGUAGE, locale/se/admin, locale/se/all, locale/se/am, + locale/se/ap, locale/se/ar, locale/se/arap, locale/se/arapprn, + locale/se/bp, locale/se/ca, locale/se/cp, locale/se/ct, + locale/se/gl, locale/se/hr, locale/se/ic, locale/se/io, + locale/se/ir, locale/se/is, locale/se/login, locale/se/menu, + locale/se/oe, locale/se/pe, locale/se/pos, locale/se/ps, + locale/se/pw, locale/se/rc, locale/se/rp, locale/sv/COPYING, + locale/sv/LANGUAGE, locale/sv/admin, locale/sv/all, locale/sv/am, + locale/sv/ap, locale/sv/ar, locale/sv/arap, locale/sv/arapprn, + locale/sv/bp, locale/sv/ca, locale/sv/cp, locale/sv/ct, + locale/sv/gl, locale/sv/hr, locale/sv/ic, locale/sv/io, + locale/sv/ir, locale/sv/is, locale/sv/login, locale/sv/menu, + locale/sv/oe, locale/sv/pe, locale/sv/pos, locale/sv/ps, + locale/sv/pw, locale/sv/rc, locale/sv/rp, locale/tr/COPYING, + locale/tr/LANGUAGE, locale/tr/admin, locale/tr/all, locale/tr/am, + locale/tr/ap, locale/tr/ar, locale/tr/arap, locale/tr/arapprn, + locale/tr/bp, locale/tr/ca, locale/tr/cp, locale/tr/ct, + locale/tr/gl, locale/tr/hr, locale/tr/ic, locale/tr/io, + locale/tr/ir, locale/tr/is, locale/tr/login, locale/tr/menu, + locale/tr/oe, locale/tr/pe, locale/tr/pos, locale/tr/ps, + locale/tr/pw, locale/tr/rc, locale/tr/rp, locale/tw_big5/COPYING, + locale/tw_big5/LANGUAGE, locale/tw_big5/admin, + locale/tw_big5/all, locale/tw_big5/am, locale/tw_big5/ap, + locale/tw_big5/ar, locale/tw_big5/arap, locale/tw_big5/arapprn, + locale/tw_big5/bp, locale/tw_big5/ca, locale/tw_big5/cp, + locale/tw_big5/ct, locale/tw_big5/gl, locale/tw_big5/hr, + locale/tw_big5/ic, locale/tw_big5/io, locale/tw_big5/ir, + locale/tw_big5/is, locale/tw_big5/login, locale/tw_big5/menu, + locale/tw_big5/oe, locale/tw_big5/pe, locale/tw_big5/pos, + locale/tw_big5/ps, locale/tw_big5/pw, locale/tw_big5/rc, + locale/tw_big5/rp, locale/tw_big5/temp, locale/tw_utf/COPYING, + locale/tw_utf/LANGUAGE, locale/tw_utf/admin, locale/tw_utf/all, + locale/tw_utf/am, locale/tw_utf/ap, locale/tw_utf/ar, + locale/tw_utf/arap, locale/tw_utf/arapprn, locale/tw_utf/bp, + locale/tw_utf/ca, locale/tw_utf/cp, locale/tw_utf/ct, + locale/tw_utf/gl, locale/tw_utf/hr, locale/tw_utf/ic, + locale/tw_utf/io, locale/tw_utf/ir, locale/tw_utf/is, + locale/tw_utf/login, locale/tw_utf/menu, locale/tw_utf/oe, + locale/tw_utf/pe, locale/tw_utf/pos, locale/tw_utf/ps, + locale/tw_utf/pw, locale/tw_utf/rc, locale/tw_utf/rp, + locale/ua/COPYING, locale/ua/LANGUAGE, locale/ua/admin, + locale/ua/all, locale/ua/am, locale/ua/ap, locale/ua/ar, + locale/ua/arap, locale/ua/arapprn, locale/ua/bp, locale/ua/ca, + locale/ua/cp, locale/ua/ct, locale/ua/gl, locale/ua/hr, + locale/ua/ic, locale/ua/io, locale/ua/ir, locale/ua/is, + locale/ua/login, locale/ua/menu, locale/ua/oe, locale/ua/pe, + locale/ua/pos, locale/ua/ps, locale/ua/pw, locale/ua/rc, + locale/ua/rp, locale/ve/COPYING, locale/ve/LANGUAGE, + locale/ve/admin, locale/ve/all, locale/ve/am, locale/ve/ap, + locale/ve/ar, locale/ve/arap, locale/ve/arapprn, locale/ve/bp, + locale/ve/ca, locale/ve/cp, locale/ve/ct, locale/ve/gl, + locale/ve/hr, locale/ve/ic, locale/ve/io, locale/ve/ir, + locale/ve/is, locale/ve/login, locale/ve/menu, locale/ve/oe, + locale/ve/pe, locale/ve/pos, locale/ve/ps, locale/ve/pw, + locale/ve/rc, locale/ve/rp, sql/Austria-chart.sql, + sql/Austria-gifi.sql, sql/Belgium-chart.sql, + sql/Belgium-gifi.sql, sql/Brazil_General-chart.sql, + sql/Canada-English-gifi.sql, + sql/Canada-English_General-chart.sql, sql/Canada-French-gifi.sql, + sql/Colombia-PUC-chart.sql, sql/Colombia-PUC-gifi.sql, + sql/Czech-Republic-chart.sql, sql/DB2-create.sql, + sql/DB2-indices.sql, sql/DB2-remove.sql, sql/DB2-set.sql, + sql/DB2-sql-ledger.order, sql/DB2-tables.sql, + sql/Danish_Default-chart.sql, sql/Default-chart.sql, + sql/Dutch_Default-chart.sql, sql/Dutch_Standard-chart.sql, + sql/Egypt-chart.sql, sql/France-chart.sql, + sql/German-Sample-chart.sql, sql/German-Sample-gifi.sql, + sql/Germany-DATEV-SKR03-chart.sql, + sql/Germany-DATEV-SKR03-gifi.sql, sql/Germany-SKR03-chart.sql, + sql/Germany-SKR03-gifi.sql, sql/Hungary-chart.sql, + sql/Hungary-gifi.sql, sql/Italy-gifi.sql, + sql/Italy_General-chart.sql, sql/Italy_cc2424-chart.sql, + sql/Latvia-chart.sql, sql/NAICS.sql, + sql/Norwegian_Default-chart.sql, sql/Oracle-indices.sql, + sql/Oracle-tables.sql, sql/Oracle-upgrade-1.8.0-1.8.4.sql, + sql/Oracle-upgrade-1.8.4-1.8.5.sql, + sql/Oracle-upgrade-1.8.5-2.0.0.sql, + sql/Oracle-upgrade-2.0.0-2.0.8.sql, + sql/Oracle-upgrade-2.0.8-2.2.0.sql, sql/Pg-functions.sql, + sql/Pg-indices.sql, sql/Pg-tables.sql, + sql/Pg-upgrade-1.2.6-1.2.7.sql, sql/Pg-upgrade-1.2.7-1.4.0.sql, + sql/Pg-upgrade-1.4.0-1.6.0.sql, sql/Pg-upgrade-1.6.0-1.8.0.sql, + sql/Pg-upgrade-1.8.0-1.8.4.sql, sql/Pg-upgrade-1.8.4-1.8.5.sql, + sql/Pg-upgrade-1.8.5-2.0.0.sql, sql/Pg-upgrade-2.0.0-2.0.8.sql, + sql/Pg-upgrade-2.0.8-2.2.0.sql, sql/Pg-upgrade-2.2.0-2.3.0.sql, + sql/Pg-upgrade-2.3.0-2.3.1.sql, sql/Pg-upgrade-2.3.1-2.3.3.sql, + sql/Pg-upgrade-2.3.3-2.3.4.sql, sql/Pg-upgrade-2.3.4-2.3.5.sql, + sql/Pg-upgrade-2.3.5-2.3.6.sql, sql/Pg-upgrade-2.3.6-2.3.7.sql, + sql/Pg-upgrade-2.3.7-2.3.8.sql, sql/Pg-upgrade-2.3.8-2.3.9.sql, + sql/Pg-upgrade-2.3.9-2.4.2.sql, sql/Pg-upgrade-2.4.2-2.4.3.sql, + sql/Pg-upgrade-2.4.3-2.4.4.sql, sql/Poland-chart.sql, + sql/Simplified-Chinese_Default-UTF8-chart.sql, + sql/Simplified-Chinese_Default-chart.sql, + sql/Spain-ISO-chart.sql, sql/Spain-UTF8-chart.sql, + sql/Swedish-chart.sql, sql/Swiss-German-chart.sql, + sql/Swiss-German-gifi.sql, + sql/Traditional-Chinese_Default-UTF8-chart.sql, + sql/Traditional-Chinese_Default-chart.sql, + sql/US_General-chart.sql, sql/US_Manufacturing-chart.sql, + sql/US_Service_Company-chart.sql, + templates/Brazilian_Portuguese-ap_transaction.html, + templates/Brazilian_Portuguese-ap_transaction.tex, + templates/Brazilian_Portuguese-ar_transaction.html, + templates/Brazilian_Portuguese-ar_transaction.tex, + templates/Brazilian_Portuguese-balance_sheet.html, + templates/Brazilian_Portuguese-bin_list.html, + templates/Brazilian_Portuguese-bin_list.tex, + templates/Brazilian_Portuguese-check.tex, + templates/Brazilian_Portuguese-income_statement.html, + templates/Brazilian_Portuguese-invoice.html, + templates/Brazilian_Portuguese-invoice.tex, + templates/Brazilian_Portuguese-packing_list.html, + templates/Brazilian_Portuguese-packing_list.tex, + templates/Brazilian_Portuguese-pick_list.html, + templates/Brazilian_Portuguese-pick_list.tex, + templates/Brazilian_Portuguese-pos_invoice.txt, + templates/Brazilian_Portuguese-purchase_order.html, + templates/Brazilian_Portuguese-purchase_order.tex, + templates/Brazilian_Portuguese-receipt.tex, + templates/Brazilian_Portuguese-request_quotation.html, + templates/Brazilian_Portuguese-request_quotation.tex, + templates/Brazilian_Portuguese-sales_order.html, + templates/Brazilian_Portuguese-sales_order.tex, + templates/Brazilian_Portuguese-sales_quotation.html, + templates/Brazilian_Portuguese-sales_quotation.tex, + templates/Brazilian_Portuguese-statement.html, + templates/Brazilian_Portuguese-statement.tex, + templates/Brazilian_Portuguese-work_order.html, + templates/Brazilian_Portuguese-work_order.tex, + templates/Danish-ap_transaction.html, + templates/Danish-ap_transaction.tex, + templates/Danish-ar_transaction.html, + templates/Danish-ar_transaction.tex, + templates/Danish-balance_sheet.html, + templates/Danish-bin_list.html, templates/Danish-bin_list.tex, + templates/Danish-check.tex, + templates/Danish-income_statement.html, + templates/Danish-invoice.html, templates/Danish-invoice.tex, + templates/Danish-packing_list.html, + templates/Danish-packing_list.tex, + templates/Danish-pick_list.html, templates/Danish-pick_list.tex, + templates/Danish-pos_invoice.txt, + templates/Danish-purchase_order.html, + templates/Danish-purchase_order.tex, + templates/Danish-receipt.tex, + templates/Danish-request_quotation.html, + templates/Danish-request_quotation.tex, + templates/Danish-sales_order.html, + templates/Danish-sales_order.tex, + templates/Danish-sales_quotation.html, + templates/Danish-sales_quotation.tex, + templates/Danish-statement.html, templates/Danish-statement.tex, + templates/Danish-work_order.html, + templates/Danish-work_order.tex, + templates/Default-ap_transaction.html, + templates/Default-ap_transaction.tex, + templates/Default-ar_transaction.html, + templates/Default-ar_transaction.tex, + templates/Default-balance_sheet.html, + templates/Default-bin_list.html, templates/Default-bin_list.tex, + templates/Default-check.tex, + templates/Default-income_statement.html, + templates/Default-invoice.html, templates/Default-invoice.tex, + templates/Default-packing_list.html, + templates/Default-packing_list.tex, + templates/Default-pick_list.html, + templates/Default-pick_list.tex, + templates/Default-pos_invoice.txt, + templates/Default-purchase_order.html, + templates/Default-purchase_order.tex, + templates/Default-receipt.tex, + templates/Default-request_quotation.html, + templates/Default-request_quotation.tex, + templates/Default-sales_order.html, + templates/Default-sales_order.tex, + templates/Default-sales_quotation.html, + templates/Default-sales_quotation.tex, + templates/Default-statement.html, + templates/Default-statement.tex, + templates/Default-work_order.html, + templates/Default-work_order.tex, + templates/Dutch-ap_transaction.html, + templates/Dutch-ap_transaction.tex, + templates/Dutch-ar_transaction.html, + templates/Dutch-ar_transaction.tex, + templates/Dutch-balance_sheet.html, + templates/Dutch-bin_list.html, templates/Dutch-bin_list.tex, + templates/Dutch-check.tex, templates/Dutch-income_statement.html, + templates/Dutch-invoice.html, templates/Dutch-invoice.tex, + templates/Dutch-packing_list.html, + templates/Dutch-packing_list.tex, templates/Dutch-pick_list.html, + templates/Dutch-pick_list.tex, templates/Dutch-pos_invoice.txt, + templates/Dutch-purchase_order.html, + templates/Dutch-purchase_order.tex, templates/Dutch-receipt.tex, + templates/Dutch-request_quotation.html, + templates/Dutch-request_quotation.tex, + templates/Dutch-sales_order.html, + templates/Dutch-sales_order.tex, + templates/Dutch-sales_quotation.html, + templates/Dutch-sales_quotation.tex, + templates/Dutch-statement.html, templates/Dutch-statement.tex, + templates/Dutch-work_order.html, templates/Dutch-work_order.tex, + templates/Estonian-ap_transaction.html, + templates/Estonian-ap_transaction.tex, + templates/Estonian-ar_transaction.html, + templates/Estonian-ar_transaction.tex, + templates/Estonian-balance_sheet.html, + templates/Estonian-bin_list.html, + templates/Estonian-bin_list.tex, templates/Estonian-check.tex, + templates/Estonian-income_statement.html, + templates/Estonian-invoice.html, templates/Estonian-invoice.tex, + templates/Estonian-packing_list.html, + templates/Estonian-packing_list.tex, + templates/Estonian-pick_list.html, + templates/Estonian-pick_list.tex, + templates/Estonian-pos_invoice.txt, + templates/Estonian-purchase_order.html, + templates/Estonian-purchase_order.tex, + templates/Estonian-receipt.tex, + templates/Estonian-request_quotation.html, + templates/Estonian-request_quotation.tex, + templates/Estonian-sales_order.html, + templates/Estonian-sales_order.tex, + templates/Estonian-statement.html, + templates/Estonian-statement.tex, + templates/Estonian-work_order.html, + templates/Estonian-work_order.tex, + templates/French-ap_transaction.html, + templates/French-ap_transaction.tex, + templates/French-ar_transaction.html, + templates/French-ar_transaction.tex, + templates/French-balance_sheet.html, + templates/French-bin_list.html, templates/French-bin_list.tex, + templates/French-check.tex, + templates/French-income_statement.html, + templates/French-invoice.html, templates/French-invoice.tex, + templates/French-packing_list.html, + templates/French-packing_list.tex, + templates/French-pick_list.html, templates/French-pick_list.tex, + templates/French-pos_invoice.txt, + templates/French-purchase_order.html, + templates/French-purchase_order.tex, + templates/French-receipt.tex, + templates/French-request_quotation.html, + templates/French-request_quotation.tex, + templates/French-sales_order.html, + templates/French-sales_order.tex, + templates/French-sales_quotation.html, + templates/French-sales_quotation.tex, + templates/French-statement.html, templates/French-statement.tex, + templates/French-work_order.html, + templates/French-work_order.tex, + templates/German-ap_transaction.html, + templates/German-ap_transaction.tex, + templates/German-ar_transaction.html, + templates/German-ar_transaction.tex, + templates/German-balance_sheet.html, + templates/German-bin_list.html, templates/German-bin_list.tex, + templates/German-check.tex, + templates/German-income_statement.html, + templates/German-invoice.html, templates/German-invoice.tex, + templates/German-packing_list.html, + templates/German-packing_list.tex, + templates/German-pick_list.html, templates/German-pick_list.tex, + templates/German-pos_invoice.txt, + templates/German-purchase_order.html, + templates/German-purchase_order.tex, + templates/German-receipt.tex, + templates/German-request_quotation.html, + templates/German-request_quotation.tex, + templates/German-sales_order.html, + templates/German-sales_order.tex, + templates/German-sales_quotation.html, + templates/German-sales_quotation.tex, + templates/German-statement.html, templates/German-statement.tex, + templates/German-work_order.html, + templates/German-work_order.tex, + templates/Hungarian-ap_transaction.html, + templates/Hungarian-ap_transaction.tex, + templates/Hungarian-ar_transaction.html, + templates/Hungarian-ar_transaction.tex, + templates/Hungarian-balance_sheet.html, + templates/Hungarian-bin_list.html, + templates/Hungarian-bin_list.tex, templates/Hungarian-check.tex, + templates/Hungarian-income_statement.html, + templates/Hungarian-invoice.html, + templates/Hungarian-invoice.tex, + templates/Hungarian-packing_list.html, + templates/Hungarian-packing_list.tex, + templates/Hungarian-pick_list.html, + templates/Hungarian-pick_list.tex, + templates/Hungarian-pos_invoice.txt, + templates/Hungarian-purchase_order.html, + templates/Hungarian-purchase_order.tex, + templates/Hungarian-receipt.tex, + templates/Hungarian-request_quotation.html, + templates/Hungarian-request_quotation.tex, + templates/Hungarian-sales_order.html, + templates/Hungarian-sales_order.tex, + templates/Hungarian-sales_quotation.html, + templates/Hungarian-sales_quotation.tex, + templates/Hungarian-statement.html, + templates/Hungarian-statement.tex, + templates/Hungarian-work_order.html, + templates/Hungarian-work_order.tex, + templates/Italian-ap_transaction.html, + templates/Italian-ap_transaction.tex, + templates/Italian-ar_transaction.html, + templates/Italian-ar_transaction.tex, + templates/Italian-balance_sheet.html, + templates/Italian-bin_list.html, templates/Italian-bin_list.tex, + templates/Italian-check.tex, + templates/Italian-income_statement.html, + templates/Italian-invoice.html, templates/Italian-invoice.tex, + templates/Italian-packing_list.html, + templates/Italian-packing_list.tex, + templates/Italian-pick_list.html, + templates/Italian-pick_list.tex, + templates/Italian-pos_invoice.txt, + templates/Italian-purchase_order.html, + templates/Italian-purchase_order.tex, + templates/Italian-receipt.tex, + templates/Italian-request_quotation.html, + templates/Italian-request_quotation.tex, + templates/Italian-sales_order.html, + templates/Italian-sales_order.tex, + templates/Italian-sales_quotation.html, + templates/Italian-sales_quotation.tex, + templates/Italian-statement.html, + templates/Italian-statement.tex, + templates/Italian-work_order.html, + templates/Italian-work_order.tex, + templates/Norwegian-ap_transaction.html, + templates/Norwegian-ap_transaction.tex, + templates/Norwegian-ar_transaction.html, + templates/Norwegian-ar_transaction.tex, + templates/Norwegian-balance_sheet.html, + templates/Norwegian-bin_list.html, + templates/Norwegian-bin_list.tex, templates/Norwegian-check.tex, + templates/Norwegian-income_statement.html, + templates/Norwegian-invoice.html, + templates/Norwegian-invoice.tex, + templates/Norwegian-packing_list.html, + templates/Norwegian-packing_list.tex, + templates/Norwegian-pick_list.html, + templates/Norwegian-pick_list.tex, + templates/Norwegian-pos_invoice.txt, + templates/Norwegian-purchase_order.html, + templates/Norwegian-purchase_order.tex, + templates/Norwegian-receipt.tex, + templates/Norwegian-request_quotation.html, + templates/Norwegian-request_quotation.tex, + templates/Norwegian-sales_order.html, + templates/Norwegian-sales_order.tex, + templates/Norwegian-sales_quotation.html, + templates/Norwegian-sales_quotation.tex, + templates/Norwegian-statement.html, + templates/Norwegian-statement.tex, + templates/Norwegian-work_order.html, + templates/Norwegian-work_order.tex, + templates/Service-ap_transaction.html, + templates/Service-ap_transaction.tex, + templates/Service-ar_transaction.html, + templates/Service-ar_transaction.tex, + templates/Service-balance_sheet.html, + templates/Service-bin_list.html, templates/Service-bin_list.tex, + templates/Service-check.tex, + templates/Service-income_statement.html, + templates/Service-invoice.html, templates/Service-invoice.tex, + templates/Service-packing_list.html, + templates/Service-packing_list.tex, + templates/Service-pick_list.html, + templates/Service-pick_list.tex, + templates/Service-pos_invoice.txt, + templates/Service-purchase_order.html, + templates/Service-purchase_order.tex, + templates/Service-receipt.tex, + templates/Service-request_quotation.html, + templates/Service-request_quotation.tex, + templates/Service-sales_order.html, + templates/Service-sales_order.tex, + templates/Service-sales_quotation.html, + templates/Service-sales_quotation.tex, + templates/Service-statement.html, + templates/Service-statement.tex, + templates/Service-work_order.html, + templates/Service-work_order.tex, + templates/Spanish_A4-ap_transaction.html, + templates/Spanish_A4-ap_transaction.tex, + templates/Spanish_A4-ar_transaction.html, + templates/Spanish_A4-ar_transaction.tex, + templates/Spanish_A4-balance_sheet.html, + templates/Spanish_A4-bin_list.html, + templates/Spanish_A4-bin_list.tex, + templates/Spanish_A4-check.tex, + templates/Spanish_A4-income_statement.html, + templates/Spanish_A4-invoice.html, + templates/Spanish_A4-invoice.tex, + templates/Spanish_A4-packing_list.html, + templates/Spanish_A4-packing_list.tex, + templates/Spanish_A4-pick_list.html, + templates/Spanish_A4-pick_list.tex, + templates/Spanish_A4-pos_invoice.txt, + templates/Spanish_A4-purchase_order.html, + templates/Spanish_A4-purchase_order.tex, + templates/Spanish_A4-receipt.tex, + templates/Spanish_A4-request_quotation.html, + templates/Spanish_A4-request_quotation.tex, + templates/Spanish_A4-sales_order.html, + templates/Spanish_A4-sales_order.tex, + templates/Spanish_A4-sales_quotation.html, + templates/Spanish_A4-sales_quotation.tex, + templates/Spanish_A4-statement.html, + templates/Spanish_A4-statement.tex, + templates/Spanish_A4-work_order.html, + templates/Spanish_A4-work_order.tex, + templates/Spanish_Letter-ap_transaction.html, + templates/Spanish_Letter-ap_transaction.tex, + templates/Spanish_Letter-ar_transaction.html, + templates/Spanish_Letter-ar_transaction.tex, + templates/Spanish_Letter-balance_sheet.html, + templates/Spanish_Letter-bin_list.html, + templates/Spanish_Letter-bin_list.tex, + templates/Spanish_Letter-check.tex, + templates/Spanish_Letter-income_statement.html, + templates/Spanish_Letter-invoice.html, + templates/Spanish_Letter-invoice.tex, + templates/Spanish_Letter-packing_list.html, + templates/Spanish_Letter-packing_list.tex, + templates/Spanish_Letter-pick_list.html, + templates/Spanish_Letter-pick_list.tex, + templates/Spanish_Letter-pos_invoice.txt, + templates/Spanish_Letter-purchase_order.html, + templates/Spanish_Letter-purchase_order.tex, + templates/Spanish_Letter-receipt.tex, + templates/Spanish_Letter-request_quotation.html, + templates/Spanish_Letter-request_quotation.tex, + templates/Spanish_Letter-sales_order.html, + templates/Spanish_Letter-sales_order.tex, + templates/Spanish_Letter-sales_quotation.html, + templates/Spanish_Letter-sales_quotation.tex, + templates/Spanish_Letter-statement.html, + templates/Spanish_Letter-statement.tex, + templates/Spanish_Letter-work_order.html, + templates/Spanish_Letter-work_order.tex, users/sql-ledger.eps, + users/sql-ledger.png: remove misplaced sql ledger update + +2004-11-13 04:50 ivan + + * sql-ledger/old/sql-ledger/: locale/en_GB/ic, locale/en_GB/io, + locale/en_GB/ir, locale/en_GB/is, locale/en_GB/login, + locale/en_GB/menu, locale/en_GB/oe, locale/en_GB/pe, + locale/en_GB/rc, locale/en_GB/rp, locale/es/COPYING, + locale/es/LANGUAGE, locale/es/Num2text, locale/es/admin, + locale/es/all, locale/es/am, locale/es/ap, locale/es/ar, + locale/es/arap, locale/es/ca, locale/es/cp, locale/es/ct, + locale/es/gl, locale/es/ic, locale/es/io, locale/es/ir, + locale/es/is, locale/es/login, locale/es/menu, locale/es/oe, + locale/es/pe, locale/es/rc, locale/es/rp, locale/fi/COPYING, + locale/fi/LANGUAGE, locale/fi/admin, locale/fi/all, locale/fi/am, + locale/fi/ap, locale/fi/ar, locale/fi/arap, locale/fi/ca, + locale/fi/cp, locale/fi/ct, locale/fi/gl, locale/fi/ic, + locale/fi/io, locale/fi/ir, locale/fi/is, locale/fi/login, + locale/fi/menu, locale/fi/oe, locale/fi/pe, locale/fi/rc, + locale/fi/rp, locale/fr/COPYING, locale/fr/LANGUAGE, + locale/fr/admin, locale/fr/all, locale/fr/am, locale/fr/ap, + locale/fr/ar, locale/fr/arap, locale/fr/ca, locale/fr/cp, + locale/fr/ct, locale/fr/gl, locale/fr/ic, locale/fr/io, + locale/fr/ir, locale/fr/is, locale/fr/login, locale/fr/menu, + locale/fr/oe, locale/fr/pe, locale/fr/rc, locale/fr/rp, + locale/hu/COPYING, locale/hu/LANGUAGE, locale/hu/admin, + locale/hu/all, locale/hu/am, locale/hu/ap, locale/hu/ar, + locale/hu/arap, locale/hu/ca, locale/hu/cp, locale/hu/ct, + locale/hu/gl, locale/hu/ic, locale/hu/io, locale/hu/ir, + locale/hu/is, locale/hu/login, locale/hu/menu, locale/hu/oe, + locale/hu/pe, locale/hu/rc, locale/hu/rp, locale/is/COPYING, + locale/is/LANGUAGE, locale/is/admin, locale/is/all, locale/is/am, + locale/is/ap, locale/is/ar, locale/is/arap, locale/is/ca, + locale/is/cp, locale/is/ct, locale/is/gl, locale/is/ic, + locale/is/io, locale/is/ir, locale/is/is, locale/is/login, + locale/is/menu, locale/is/oe, locale/is/pe, locale/is/rc, + locale/is/rp, locale/it/COPYING, locale/it/LANGUAGE, + locale/it/Num2text, locale/it/admin, locale/it/all, locale/it/am, + locale/it/ap, locale/it/ar, locale/it/arap, locale/it/ca, + locale/it/cp, locale/it/ct, locale/it/gl, locale/it/ic, + locale/it/io, locale/it/ir, locale/it/is, locale/it/login, + locale/it/menu, locale/it/oe, locale/it/pe, locale/it/qe, + locale/it/rc, locale/it/rp, locale/lt/COPYING, + locale/lt/LANGUAGE, locale/lt/admin, locale/lt/all, locale/lt/am, + locale/lt/ap, locale/lt/ar, locale/lt/arap, locale/lt/ca, + locale/lt/cp, locale/lt/ct, locale/lt/gl, locale/lt/ic, + locale/lt/io, locale/lt/ir, locale/lt/is, locale/lt/login, + locale/lt/menu, locale/lt/oe, locale/lt/pe, locale/lt/rc, + locale/lt/rp, locale/mx/COPYING, locale/mx/LANGUAGE, + locale/mx/admin, locale/mx/all, locale/mx/am, locale/mx/ap, + locale/mx/ar, locale/mx/arap, locale/mx/ca, locale/mx/cp, + locale/mx/ct, locale/mx/gl, locale/mx/ic, locale/mx/io, + locale/mx/ir, locale/mx/is, locale/mx/login, locale/mx/menu, + locale/mx/oe, locale/mx/pe, locale/mx/rc, locale/mx/rp, + locale/nl/COPYING, locale/nl/LANGUAGE, locale/nl/Num2text, + locale/nl/admin, locale/nl/all, locale/nl/am, locale/nl/ap, + locale/nl/ar, locale/nl/arap, locale/nl/ca, locale/nl/cp, + locale/nl/ct, locale/nl/gl, locale/nl/ic, locale/nl/io, + locale/nl/ir, locale/nl/is, locale/nl/login, locale/nl/menu, + locale/nl/oe, locale/nl/pe, locale/nl/rc, locale/nl/rp, + locale/no/COPYING, locale/no/LANGUAGE, locale/no/admin, + locale/no/all, locale/no/am, locale/no/ap, locale/no/ar, + locale/no/arap, locale/no/ca, locale/no/cp, locale/no/ct, + locale/no/gl, locale/no/ic, locale/no/io, locale/no/ir, + locale/no/is, locale/no/login, locale/no/menu, locale/no/oe, + locale/no/pe, locale/no/rc, locale/no/rp, locale/pa/COPYING, + locale/pa/LANGUAGE, locale/pa/admin, locale/pa/all, locale/pa/am, + locale/pa/ap, locale/pa/ar, locale/pa/arap, locale/pa/ca, + locale/pa/cp, locale/pa/ct, locale/pa/gl, locale/pa/ic, + locale/pa/io, locale/pa/ir, locale/pa/is, locale/pa/login, + locale/pa/menu, locale/pa/oe, locale/pa/pe, locale/pa/rc, + locale/pa/rp, locale/pl/COPYING, locale/pl/LANGUAGE, + locale/pl/admin, locale/pl/all, locale/pl/am, locale/pl/ap, + locale/pl/ar, locale/pl/arap, locale/pl/ca, locale/pl/cp, + locale/pl/ct, locale/pl/gl, locale/pl/ic, locale/pl/io, + locale/pl/ir, locale/pl/is, locale/pl/login, locale/pl/menu, + locale/pl/oe, locale/pl/pe, locale/pl/rc, locale/pl/rp, + locale/pt/COPYING, locale/pt/LANGUAGE, locale/pt/admin, + locale/pt/all, locale/pt/am, locale/pt/ap, locale/pt/ar, + locale/pt/arap, locale/pt/ca, locale/pt/cp, locale/pt/ct, + locale/pt/gl, locale/pt/ic, locale/pt/io, locale/pt/ir, + locale/pt/is, locale/pt/login, locale/pt/menu, locale/pt/oe, + locale/pt/pe, locale/pt/rc, locale/pt/rp, locale/ru/COPYING, + locale/ru/LANGUAGE, locale/ru/admin, locale/ru/all, locale/ru/am, + locale/ru/ap, locale/ru/ar, locale/ru/arap, locale/ru/ca, + locale/ru/cp, locale/ru/ct, locale/ru/gl, locale/ru/ic, + locale/ru/io, locale/ru/ir, locale/ru/is, locale/ru/login, + locale/ru/menu, locale/ru/oe, locale/ru/pe, locale/ru/rc, + locale/ru/rp, locale/se/COPYING, locale/se/LANGUAGE, + locale/se/admin, locale/se/all, locale/se/am, locale/se/ap, + locale/se/ar, locale/se/arap, locale/se/ca, locale/se/cp, + locale/se/ct, locale/se/gl, locale/se/ic, locale/se/io, + locale/se/ir, locale/se/is, locale/se/login, locale/se/menu, + locale/se/oe, locale/se/pe, locale/se/rc, locale/se/rp, + locale/tr/COPYING, locale/tr/LANGUAGE, locale/tr/admin, + locale/tr/all, locale/tr/am, locale/tr/ap, locale/tr/ar, + locale/tr/arap, locale/tr/ca, locale/tr/cp, locale/tr/ct, + locale/tr/gl, locale/tr/ic, locale/tr/io, locale/tr/ir, + locale/tr/is, locale/tr/login, locale/tr/menu, locale/tr/oe, + locale/tr/pe, locale/tr/rc, locale/tr/rp, locale/tw/COPYING, + locale/tw/LANGUAGE, locale/tw/admin, locale/tw/all, locale/tw/am, + locale/tw/ap, locale/tw/ar, locale/tw/arap, locale/tw/ca, + locale/tw/cp, locale/tw/ct, locale/tw/gl, locale/tw/ic, + locale/tw/io, locale/tw/ir, locale/tw/is, locale/tw/login, + locale/tw/menu, locale/tw/oe, locale/tw/pe, locale/tw/rc, + locale/tw/rp, locale/ua/COPYING, locale/ua/LANGUAGE, + locale/ua/admin, locale/ua/all, locale/ua/am, locale/ua/ap, + locale/ua/ar, locale/ua/arap, locale/ua/ca, locale/ua/cp, + locale/ua/ct, locale/ua/gl, locale/ua/ic, locale/ua/io, + locale/ua/ir, locale/ua/is, locale/ua/login, locale/ua/menu, + locale/ua/oe, locale/ua/pe, locale/ua/rc, locale/ua/rp, + locale/ve/COPYING, locale/ve/LANGUAGE, locale/ve/admin, + locale/ve/all, locale/ve/am, locale/ve/ap, locale/ve/ar, + locale/ve/arap, locale/ve/ca, locale/ve/cp, locale/ve/ct, + locale/ve/gl, locale/ve/ic, locale/ve/io, locale/ve/ir, + locale/ve/is, locale/ve/login, locale/ve/menu, locale/ve/oe, + locale/ve/pe, locale/ve/rc, locale/ve/rp, sql/Austria-chart.sql, + sql/Austria-gifi.sql, sql/Brazil_General-chart.sql, + sql/Canada_General-chart.sql, sql/Canada-gifi.sql, + sql/Germany-DATEV-SKR03-chart.sql, sql/Czech_Republic-chart.sql, + sql/Danish_Default-chart.sql, sql/Default-chart.sql, + sql/Dutch_Default-chart.sql, sql/Dutch_Standard-chart.sql, + sql/France-chart.sql, sql/German-Sample-chart.sql, + sql/German-Sample-gifi.sql, sql/Oracle-upgrade-1.8.0-1.8.4.sql, + sql/Germany-DATEV-SKR03-gifi.sql, sql/Germany-SKR03-chart.sql, + sql/Germany-SKR03-gifi.sql, sql/Italy-chart.sql, + sql/Oracle-indices.sql, sql/Oracle-tables.sql, + sql/Oracle-upgrade-1.8.4-1.8.5.sql, + sql/Oracle-upgrade-1.8.5-2.0.0.sql, + sql/Oracle-upgrade-2.0.0-2.0.8.sql, sql/Pg-indices.sql, + sql/Pg-tables.sql, sql/Pg-upgrade-1.2.6-1.2.7.sql, + sql/Simplified_Chinese_Default-chart.sql, + sql/Pg-upgrade-1.2.7-1.4.0.sql, sql/Pg-upgrade-1.4.0-1.6.0.sql, + sql/Pg-upgrade-1.6.0-1.8.0.sql, sql/Pg-upgrade-1.8.0-1.8.4.sql, + sql/Pg-upgrade-1.8.4-1.8.5.sql, sql/Pg-upgrade-1.8.5-2.0.0.sql, + sql/Pg-upgrade-2.0.0-2.0.8.sql, sql/Poland-chart.sql, + sql/Swiss-German-chart.sql, sql/Spain-chart.sql, + sql/Swiss-German-gifi.sql, + sql/Traditional_Chinese_Default-chart.sql, + sql/US_General-chart.sql, + templates/Brazilian_Portuguese-balance_sheet.html, + templates/Brazilian_Portuguese-check.tex, + templates/Brazilian_Portuguese-income_statement.html, + templates/Brazilian_Portuguese-invoice.html, + templates/Brazilian_Portuguese-packing_list.html, + templates/Brazilian_Portuguese-invoice.tex, + templates/Brazilian_Portuguese-packing_list.tex, + templates/Brazilian_Portuguese-purchase_order.html, + templates/Brazilian_Portuguese-purchase_order.tex, + templates/Brazilian_Portuguese-receipt.tex, + templates/Brazilian_Portuguese-sales_order.html, + templates/Danish-check.tex, templates/Danish-invoice.html, + templates/Brazilian_Portuguese-sales_order.tex, + templates/Brazilian_Portuguese-statement.html, + templates/Brazilian_Portuguese-statement.tex, + templates/Danish-balance_sheet.html, + templates/Danish-income_statement.html, + templates/Danish-invoice.tex, templates/Danish-packing_list.html, + templates/Danish-packing_list.tex, + templates/Danish-purchase_order.html, + templates/Default-income_statement.html, + templates/Danish-purchase_order.tex, + templates/Danish-receipt.tex, templates/Danish-sales_order.html, + templates/Danish-sales_order.tex, + templates/Danish-statement.html, templates/Danish-statement.tex, + templates/Default-balance_sheet.html, + templates/Default-check.tex, templates/Default-invoice.html, + templates/Default-invoice.tex, + templates/Default-packing_list.html, + templates/Default-packing_list.tex, + templates/Default-purchase_order.html, + templates/Default-purchase_order.tex, + templates/Default-receipt.tex, + templates/Default-sales_order.html, + templates/Default-sales_order.tex, + templates/Default-statement.html, + templates/Default-statement.tex, + templates/Dutch-balance_sheet.html, templates/Dutch-check.tex, + templates/Dutch-income_statement.html, + templates/Estonian-income_statement.html, + templates/Dutch-invoice.html, templates/Dutch-invoice.tex, + templates/Dutch-packing_list.html, + templates/Dutch-packing_list.tex, + templates/Dutch-purchase_order.html, + templates/Dutch-purchase_order.tex, templates/Dutch-receipt.tex, + templates/Dutch-sales_order.html, + templates/Dutch-sales_order.tex, templates/Dutch-statement.html, + templates/Dutch-statement.tex, + templates/Estonian-balance_sheet.html, + templates/Estonian-check.tex, templates/Estonian-invoice.html, + templates/Estonian-invoice.tex, + templates/Estonian-packing_list.html, + templates/Estonian-packing_list.tex, + templates/Estonian-purchase_order.html, + templates/Estonian-purchase_order.tex, + templates/Estonian-receipt.tex, + templates/Service-income_statement.html, + templates/Estonian-sales_order.html, + templates/Estonian-sales_order.tex, + templates/Estonian-statement.html, + templates/Estonian-statement.tex, + templates/French-balance_sheet.html, templates/French-check.tex, + templates/French-income_statement.html, + templates/French-invoice.html, templates/French-invoice.tex, + templates/French-packing_list.html, + templates/French-packing_list.tex, + templates/French-purchase_order.html, + templates/French-purchase_order.tex, + templates/French-receipt.tex, templates/French-sales_order.html, + templates/French-sales_order.tex, + templates/French-statement.html, templates/French-statement.tex, + templates/German-balance_sheet.html, templates/German-check.tex, + templates/German-income_statement.html, + templates/German-invoice.html, templates/German-invoice.tex, + templates/German-packing_list.html, + templates/German-packing_list.tex, + templates/German-purchase_order.html, + templates/German-purchase_order.tex, + templates/German-receipt.tex, templates/German-sales_order.html, + templates/German-sales_order.tex, + templates/German-statement.html, templates/German-statement.tex, + templates/Service-balance_sheet.html, + templates/Service-check.tex, templates/Service-invoice.html, + templates/Service-invoice.tex, + templates/Service-packing_list.html, + templates/Service-packing_list.tex, + templates/Service-purchase_order.html, + templates/Service-purchase_order.tex, + templates/Service-receipt.tex, + templates/Service-sales_order.html, + templates/Spanish_A4-balance_sheet.html, + templates/Service-sales_order.tex, + templates/Service-statement.html, + templates/Service-statement.tex, templates/Spanish_A4-check.tex, + templates/Spanish_A4-income_statement.html, + templates/Spanish_A4-invoice.html, + templates/Spanish_A4-invoice.tex, + templates/Spanish_A4-packing_list.html, + templates/Spanish_A4-packing_list.tex, + templates/Spanish_Letter-balance_sheet.html, + templates/Spanish_A4-purchase_order.html, + templates/Spanish_A4-purchase_order.tex, + templates/Spanish_A4-receipt.tex, + templates/Spanish_A4-sales_order.html, + templates/Spanish_A4-sales_order.tex, + templates/Spanish_A4-statement.html, + templates/Spanish_A4-statement.tex, + templates/Spanish_Letter-check.tex, + templates/Spanish_Letter-invoice.html, + templates/Spanish_Letter-income_statement.html, + templates/Spanish_Letter-invoice.tex, + templates/Spanish_Letter-packing_list.html, + templates/Spanish_Letter-packing_list.tex, + templates/Spanish_Letter-purchase_order.html, + templates/Spanish_Letter-purchase_order.tex, + templates/Spanish_Letter-receipt.tex, + templates/Spanish_Letter-sales_order.html, + templates/Spanish_Letter-sales_order.tex, + templates/Spanish_Letter-statement.html, + templates/Spanish_Letter-statement.tex, users/members.default: + Initial revision + +2004-11-13 04:47 ivan + + * sql-ledger/: sql-ledger/locale/ru/arap, sql-ledger/locale/ru/bp, + sql-ledger/locale/ru/cp, sql-ledger/locale/ru/oe, + sql-ledger/locale/ru/pe, sql-ledger/locale/ru/pos, + sql-ledger/locale/ru/rc, sql-ledger/locale/ru/arapprn, + sql-ledger/locale/ru/hr, sql-ledger/locale/ru/ps, + sql-ledger/locale/ru/pw, sql-ledger/locale/ua/COPYING, + sql-ledger/locale/ua/LANGUAGE, sql-ledger/locale/ua/admin, + sql-ledger/locale/ua/all, sql-ledger/locale/ua/am, + sql-ledger/locale/ua/ap, sql-ledger/locale/ua/ar, + sql-ledger/locale/ua/ca, sql-ledger/locale/ua/ct, + sql-ledger/locale/ua/gl, sql-ledger/locale/ua/ic, + sql-ledger/locale/ua/ir, sql-ledger/locale/ua/io, + sql-ledger/locale/ua/login, sql-ledger/locale/ua/menu, + sql-ledger/locale/ua/rp, sql-ledger/locale/ua/arap, + sql-ledger/locale/ua/bp, sql-ledger/locale/ua/cp, + sql-ledger/locale/ua/is, sql-ledger/locale/ua/oe, + sql-ledger/locale/ua/pe, sql-ledger/locale/ua/pos, + sql-ledger/locale/ua/rc, sql-ledger/locale/ua/arapprn, + sql-ledger/locale/ua/hr, sql-ledger/locale/ua/ps, + sql-ledger/locale/ua/pw, sql-ledger/locale/se/COPYING, + sql-ledger/locale/se/LANGUAGE, sql-ledger/locale/se/all, + sql-ledger/locale/se/admin, sql-ledger/locale/se/am, + sql-ledger/locale/se/ap, sql-ledger/locale/se/ar, + sql-ledger/locale/se/ca, sql-ledger/locale/se/ct, + sql-ledger/locale/se/gl, sql-ledger/locale/se/ic, + sql-ledger/locale/se/io, sql-ledger/locale/se/ir, + sql-ledger/locale/se/login, sql-ledger/locale/se/menu, + sql-ledger/locale/se/rp, sql-ledger/locale/se/arap, + sql-ledger/locale/se/is, sql-ledger/locale/se/oe, + sql-ledger/locale/se/pe, sql-ledger/locale/se/arapprn, + sql-ledger/locale/se/bp, sql-ledger/locale/se/cp, + sql-ledger/locale/se/hr, sql-ledger/locale/se/pos, + sql-ledger/locale/se/ps, sql-ledger/locale/se/pw, + sql-ledger/locale/se/rc, sql-ledger/locale/hu/COPYING, + sql-ledger/locale/hu/LANGUAGE, sql-ledger/locale/hu/admin, + sql-ledger/locale/hu/all, sql-ledger/locale/hu/am, + sql-ledger/locale/hu/ap, sql-ledger/locale/hu/ar, + sql-ledger/locale/hu/ca, sql-ledger/locale/hu/ct, + sql-ledger/locale/hu/gl, sql-ledger/locale/hu/ic, + sql-ledger/locale/hu/io, sql-ledger/locale/hu/ir, + sql-ledger/locale/hu/is, sql-ledger/locale/hu/login, + sql-ledger/locale/hu/menu, sql-ledger/locale/hu/rp, + sql-ledger/locale/hu/arap, sql-ledger/locale/hu/cp, + sql-ledger/locale/hu/oe, sql-ledger/locale/hu/pe, + sql-ledger/locale/hu/rc, sql-ledger/locale/hu/Num2text, + sql-ledger/locale/hu/arapprn, sql-ledger/locale/hu/bp, + sql-ledger/locale/hu/hr, sql-ledger/locale/hu/pos, + sql-ledger/locale/hu/ps, sql-ledger/locale/hu/pw, + sql-ledger/locale/lt/COPYING, sql-ledger/locale/lt/LANGUAGE, + sql-ledger/locale/lt/admin, sql-ledger/locale/lt/all, + sql-ledger/locale/lt/am, sql-ledger/locale/lt/ap, + sql-ledger/locale/lt/ar, sql-ledger/locale/lt/ca, + sql-ledger/locale/lt/ct, sql-ledger/locale/lt/gl, + sql-ledger/locale/lt/ic, sql-ledger/locale/lt/ir, + sql-ledger/locale/lt/io, sql-ledger/locale/lt/is, + sql-ledger/locale/lt/login, sql-ledger/locale/lt/menu, + sql-ledger/locale/lt/rp, sql-ledger/locale/lt/arap, + sql-ledger/locale/lt/cp, sql-ledger/locale/lt/oe, + sql-ledger/locale/lt/pe, sql-ledger/locale/lt/rc, + sql-ledger/locale/is/COPYING, sql-ledger/locale/is/LANGUAGE, + sql-ledger/locale/lt/arapprn, sql-ledger/locale/lt/bp, + sql-ledger/locale/lt/hr, sql-ledger/locale/lt/pos, + sql-ledger/locale/lt/ps, sql-ledger/locale/lt/pw, + sql-ledger/locale/is/all, sql-ledger/locale/is/admin, + sql-ledger/locale/is/am, sql-ledger/locale/is/ap, + sql-ledger/locale/is/ar, sql-ledger/locale/is/ca, + sql-ledger/locale/is/ct, sql-ledger/locale/is/gl, + sql-ledger/locale/is/ic, sql-ledger/locale/is/io, + sql-ledger/locale/is/ir, sql-ledger/locale/is/login, + sql-ledger/locale/is/menu, sql-ledger/locale/is/rp, + sql-ledger/locale/is/arap, sql-ledger/locale/is/cp, + sql-ledger/locale/is/is, sql-ledger/locale/is/oe, + sql-ledger/locale/is/pe, sql-ledger/locale/is/bp, + sql-ledger/locale/is/pos, sql-ledger/locale/is/rc, + sql-ledger/locale/es_iso/admin, sql-ledger/locale/es_iso/login, + sql-ledger/locale/is/arapprn, sql-ledger/locale/is/hr, + sql-ledger/locale/is/ps, sql-ledger/locale/is/pw, + sql-ledger/locale/es_iso/all, sql-ledger/locale/es_iso/ar, + sql-ledger/locale/es_iso/ct, sql-ledger/locale/es_iso/gl, + sql-ledger/locale/es_iso/ic, sql-ledger/locale/es_iso/ir, + sql-ledger/locale/es_iso/ap, sql-ledger/locale/es_iso/ca, + sql-ledger/locale/es_iso/is, sql-ledger/locale/es_iso/menu, + sql-ledger/locale/es_iso/rp, sql-ledger/locale/es_iso/LANGUAGE, + sql-ledger/locale/es_iso/am, sql-ledger/locale/es_iso/io, + sql-ledger/locale/es_iso/COPYING, + sql-ledger/locale/es_iso/Num2text, sql-ledger/locale/es_iso/arap, + sql-ledger/locale/es_iso/bp, sql-ledger/locale/es_iso/cp, + sql-ledger/locale/es_iso/oe, sql-ledger/locale/es_iso/pe, + sql-ledger/locale/es_iso/pos, sql-ledger/locale/es_iso/rc, + sql-ledger/locale/es_iso/arapprn, sql-ledger/locale/es_iso/hr, + sql-ledger/locale/es_iso/ps, sql-ledger/locale/es_iso/pw, + sql-ledger/locale/lv/COPYING, sql-ledger/locale/lv/LANGUAGE, + sql-ledger/locale/lv/admin, sql-ledger/locale/lv/all, + sql-ledger/locale/lv/am, sql-ledger/locale/lv/ap, + sql-ledger/locale/lv/ar, sql-ledger/locale/lv/ca, + sql-ledger/locale/lv/ct, sql-ledger/locale/lv/gl, + sql-ledger/locale/lv/ic, sql-ledger/locale/lv/io, + sql-ledger/locale/lv/ir, sql-ledger/locale/lv/login, + sql-ledger/locale/lv/menu, sql-ledger/locale/lv/is, + sql-ledger/locale/lv/rp, sql-ledger/locale/lv/arap, + sql-ledger/locale/lv/bp, sql-ledger/locale/lv/cp, + sql-ledger/locale/lv/oe, sql-ledger/locale/lv/pe, + sql-ledger/locale/lv/pos, sql-ledger/locale/lv/rc, + sql-ledger/locale/es_utf/admin, sql-ledger/locale/es_utf/login, + sql-ledger/locale/lv/arapprn, sql-ledger/locale/lv/hr, + sql-ledger/locale/lv/ps, sql-ledger/locale/lv/pw, + sql-ledger/locale/es_utf/all, sql-ledger/locale/es_utf/ar, + sql-ledger/locale/es_utf/ct, sql-ledger/locale/es_utf/gl, + sql-ledger/locale/es_utf/ic, sql-ledger/locale/es_utf/ap, + sql-ledger/locale/es_utf/ir, sql-ledger/locale/es_utf/is, + sql-ledger/locale/es_utf/menu, sql-ledger/locale/es_utf/rp, + sql-ledger/locale/es_utf/LANGUAGE, sql-ledger/locale/es_utf/am, + sql-ledger/locale/es_utf/ca, sql-ledger/locale/es_utf/io, + sql-ledger/locale/es_utf/oe, sql-ledger/locale/es_utf/COPYING, + sql-ledger/locale/es_utf/Num2text, sql-ledger/locale/es_utf/arap, + sql-ledger/locale/es_utf/bp, sql-ledger/locale/es_utf/cp, + sql-ledger/locale/es_utf/pe, sql-ledger/locale/es_utf/pos, + sql-ledger/locale/es_utf/rc, sql-ledger/locale/en_GB/admin, + sql-ledger/locale/en_GB/am, sql-ledger/locale/es_utf/arapprn, + sql-ledger/locale/es_utf/hr, sql-ledger/locale/es_utf/ps, + sql-ledger/locale/es_utf/pw, sql-ledger/locale/en_GB/ap, + sql-ledger/locale/en_GB/ar, sql-ledger/locale/en_GB/ca, + sql-ledger/locale/en_GB/ct, sql-ledger/locale/en_GB/gl, + sql-ledger/locale/en_GB/ic, sql-ledger/locale/en_GB/io, + sql-ledger/locale/en_GB/ir, sql-ledger/locale/en_GB/is, + sql-ledger/locale/en_GB/login, sql-ledger/locale/en_GB/menu, + sql-ledger/locale/en_GB/rp, sql-ledger/locale/en_GB/COPYING, + sql-ledger/locale/en_GB/LANGUAGE, sql-ledger/locale/en_GB/arap, + sql-ledger/locale/en_GB/bp, sql-ledger/locale/en_GB/cp, + sql-ledger/locale/en_GB/oe, sql-ledger/locale/en_GB/pe, + sql-ledger/locale/en_GB/rc, sql-ledger/locale/eg/COPYING, + sql-ledger/locale/eg/LANGUAGE, sql-ledger/locale/en_GB/all, + sql-ledger/locale/en_GB/arapprn, sql-ledger/locale/en_GB/hr, + sql-ledger/locale/en_GB/pos, sql-ledger/locale/en_GB/ps, + sql-ledger/locale/en_GB/pw, sql-ledger/locale/eg/admin, + sql-ledger/locale/eg/all, sql-ledger/locale/eg/am, + sql-ledger/locale/eg/ap, sql-ledger/locale/eg/ar, + sql-ledger/locale/eg/arap, sql-ledger/locale/eg/bp, + sql-ledger/locale/eg/ca, sql-ledger/locale/eg/cp, + sql-ledger/locale/eg/ct, sql-ledger/locale/eg/gl, + sql-ledger/locale/eg/ic, sql-ledger/locale/eg/io, + sql-ledger/locale/eg/ir, sql-ledger/locale/eg/is, + sql-ledger/locale/eg/login, sql-ledger/locale/eg/menu, + sql-ledger/locale/eg/hr, sql-ledger/locale/eg/oe, + sql-ledger/locale/eg/arapprn, sql-ledger/locale/eg/pe, + sql-ledger/locale/eg/pos, sql-ledger/locale/eg/ps, + sql-ledger/locale/eg/pw, sql-ledger/locale/eg/rc, + sql-ledger/locale/eg/rp, sql-ledger/locale/sv/COPYING, + sql-ledger/locale/sv/LANGUAGE, sql-ledger/locale/sv/admin, + sql-ledger/locale/sv/all, sql-ledger/locale/sv/am, + sql-ledger/locale/sv/ap, sql-ledger/locale/sv/ar, + sql-ledger/locale/sv/ca, sql-ledger/locale/sv/ct, + sql-ledger/locale/sv/gl, sql-ledger/locale/sv/ic, + sql-ledger/locale/sv/io, sql-ledger/locale/sv/ir, + sql-ledger/locale/sv/login, sql-ledger/locale/sv/menu, + sql-ledger/locale/sv/is, sql-ledger/locale/sv/oe, + sql-ledger/locale/sv/rp, sql-ledger/locale/sv/arap, + sql-ledger/locale/sv/cp, sql-ledger/locale/sv/pe, + sql-ledger/locale/sv/pos, sql-ledger/locale/sv/rc, + sql-ledger/locale/nb/admin, sql-ledger/locale/sv/arapprn, + sql-ledger/locale/sv/bp, sql-ledger/locale/sv/hr, + sql-ledger/locale/sv/ps, sql-ledger/locale/sv/pw, + sql-ledger/locale/nb/all, sql-ledger/locale/nb/am, + sql-ledger/locale/nb/ap, sql-ledger/locale/nb/ar, + sql-ledger/locale/nb/ca, sql-ledger/locale/nb/ct, + sql-ledger/locale/nb/gl, sql-ledger/locale/nb/ic, + sql-ledger/locale/nb/ir, sql-ledger/locale/nb/COPYING, + sql-ledger/locale/nb/io, sql-ledger/locale/nb/is, + sql-ledger/locale/nb/login, sql-ledger/locale/nb/menu, + sql-ledger/locale/nb/rp, sql-ledger/locale/nb/LANGUAGE, + sql-ledger/locale/nb/arap, sql-ledger/locale/nb/bp, + sql-ledger/locale/nb/cp, sql-ledger/locale/nb/oe, + sql-ledger/locale/nb/pe, sql-ledger/locale/nb/rc, + sql-ledger/locale/nb/arapprn, sql-ledger/locale/nb/hr, + sql-ledger/locale/nb/pos, sql-ledger/locale/nb/ps, + sql-ledger/locale/nb/pw, sql-ledger/locale/tw_utf/admin, + sql-ledger/locale/tw_utf/all, sql-ledger/locale/tw_utf/COPYING, + sql-ledger/locale/tw_utf/am, sql-ledger/locale/tw_utf/ap, + sql-ledger/locale/tw_utf/ar, sql-ledger/locale/tw_utf/arap, + sql-ledger/locale/tw_utf/bp, sql-ledger/locale/tw_utf/ca, + sql-ledger/locale/tw_utf/cp, sql-ledger/locale/tw_utf/ct, + sql-ledger/locale/tw_utf/gl, sql-ledger/locale/tw_utf/hr, + sql-ledger/locale/tw_utf/ic, sql-ledger/locale/tw_utf/io, + sql-ledger/locale/tw_utf/ir, sql-ledger/locale/tw_utf/LANGUAGE, + sql-ledger/locale/tw_utf/is, sql-ledger/locale/tw_utf/login, + sql-ledger/locale/tw_utf/menu, sql-ledger/locale/tw_utf/oe, + sql-ledger/locale/tw_utf/pe, sql-ledger/locale/tw_utf/pos, + sql-ledger/locale/tw_utf/ps, sql-ledger/locale/tw_utf/rc, + sql-ledger/locale/tw_utf/rp, sql-ledger/locale/tw_big5/admin, + sql-ledger/locale/tw_utf/arapprn, sql-ledger/locale/tw_utf/pw, + sql-ledger/locale/tw_big5/all, sql-ledger/locale/tw_big5/am, + sql-ledger/locale/tw_big5/COPYING, sql-ledger/locale/tw_big5/ap, + sql-ledger/locale/tw_big5/ar, sql-ledger/locale/tw_big5/arap, + sql-ledger/locale/tw_big5/bp, sql-ledger/locale/tw_big5/ca, + sql-ledger/locale/tw_big5/cp, sql-ledger/locale/tw_big5/ct, + sql-ledger/locale/tw_big5/gl, sql-ledger/locale/tw_big5/hr, + sql-ledger/locale/tw_big5/ic, sql-ledger/locale/tw_big5/io, + sql-ledger/locale/tw_big5/LANGUAGE, sql-ledger/locale/tw_big5/ir, + sql-ledger/locale/tw_big5/is, sql-ledger/locale/tw_big5/login, + sql-ledger/locale/tw_big5/menu, sql-ledger/locale/tw_big5/oe, + sql-ledger/locale/tw_big5/pe, sql-ledger/locale/tw_big5/pos, + sql-ledger/locale/tw_big5/arapprn, sql-ledger/locale/tw_big5/ps, + sql-ledger/locale/tw_big5/pw, sql-ledger/locale/tw_big5/rc, + sql-ledger/locale/tw_big5/rp, sql-ledger/locale/tw_big5/temp, + sql-ledger/locale/be_nl/admin, sql-ledger/locale/be_nl/all, + sql-ledger/locale/be_nl/am, sql-ledger/locale/be_nl/ap, + sql-ledger/locale/be_nl/ar, sql-ledger/locale/be_nl/ca, + sql-ledger/locale/be_nl/ct, sql-ledger/locale/be_nl/gl, + sql-ledger/locale/be_nl/ic, sql-ledger/locale/be_nl/ir, + sql-ledger/locale/be_nl/is, sql-ledger/locale/be_nl/login, + sql-ledger/locale/be_nl/menu, sql-ledger/locale/be_nl/io, + sql-ledger/locale/be_nl/rp, sql-ledger/locale/be_nl/COPYING, + sql-ledger/locale/be_nl/LANGUAGE, + sql-ledger/locale/be_nl/Num2text, sql-ledger/locale/be_nl/arap, + sql-ledger/locale/be_nl/bp, sql-ledger/locale/be_nl/cp, + sql-ledger/locale/be_nl/oe, sql-ledger/locale/be_nl/pe, + sql-ledger/locale/be_nl/pos, sql-ledger/locale/be_nl/rc, + sql-ledger/locale/be_nl/hr, sql-ledger/locale/be_nl/ps, + sql-ledger/locale/be_nl/arapprn, sql-ledger/locale/be_nl/pw, + sql-ledger/locale/cn_utf/admin, sql-ledger/locale/cn_utf/all, + sql-ledger/locale/cn_utf/am, sql-ledger/locale/cn_utf/ap, + sql-ledger/locale/cn_utf/ar, sql-ledger/locale/cn_utf/COPYING, + sql-ledger/locale/cn_utf/arap, sql-ledger/locale/cn_utf/bp, + sql-ledger/locale/cn_utf/ca, sql-ledger/locale/cn_utf/cp, + sql-ledger/locale/cn_utf/ct, sql-ledger/locale/cn_utf/gl, + sql-ledger/locale/cn_utf/hr, sql-ledger/locale/cn_utf/ic, + sql-ledger/locale/cn_utf/io, sql-ledger/locale/cn_utf/LANGUAGE, + sql-ledger/locale/cn_utf/ir, sql-ledger/locale/cn_utf/is, + sql-ledger/locale/cn_utf/login, sql-ledger/locale/cn_utf/menu, + sql-ledger/locale/cn_utf/oe, sql-ledger/locale/cn_utf/pe, + sql-ledger/locale/cn_utf/pos, sql-ledger/locale/cn_utf/arapprn, + sql-ledger/locale/cn_utf/ps, sql-ledger/locale/cn_utf/pw, + sql-ledger/locale/cn_utf/rc, sql-ledger/locale/cn_utf/rp, + sql-ledger/locale/gr/COPYING, sql-ledger/locale/gr/LANGUAGE, + sql-ledger/locale/gr/all, sql-ledger/locale/gr/admin, + sql-ledger/locale/gr/am, sql-ledger/locale/gr/ap, + sql-ledger/locale/gr/ar, sql-ledger/locale/gr/ca, + sql-ledger/locale/gr/ct, sql-ledger/locale/gr/gl, + sql-ledger/locale/gr/ic, sql-ledger/locale/gr/ir, + sql-ledger/locale/gr/io, sql-ledger/locale/gr/is, + sql-ledger/locale/gr/login, sql-ledger/locale/gr/menu, + sql-ledger/locale/gr/rp, sql-ledger/locale/gr/arap, + sql-ledger/locale/gr/arapprn, sql-ledger/locale/gr/bp, + sql-ledger/locale/gr/cp, sql-ledger/locale/gr/hr, + sql-ledger/locale/gr/oe, sql-ledger/locale/gr/pe, + sql-ledger/locale/gr/pos, sql-ledger/locale/gr/ps, + sql-ledger/locale/gr/pw, sql-ledger/locale/gr/rc, + old/sql-ledger/VERSION, old/sql-ledger/am.pl, + old/sql-ledger/favicon.ico, old/sql-ledger/login.pl, + old/sql-ledger/menu.ini, old/sql-ledger/sql-ledger.png, + old/sql-ledger/setup.pl, old/sql-ledger/sql-ledger.conf.default, + old/sql-ledger/SL/AM.pm, old/sql-ledger/SL/Inifile.pm, + old/sql-ledger/SL/AP.pm, old/sql-ledger/SL/AR.pm, + old/sql-ledger/SL/CA.pm, old/sql-ledger/SL/CP.pm, + old/sql-ledger/SL/CT.pm, old/sql-ledger/SL/Form.pm, + old/sql-ledger/SL/GL.pm, old/sql-ledger/SL/IC.pm, + old/sql-ledger/SL/IR.pm, old/sql-ledger/SL/IS.pm, + old/sql-ledger/SL/Mailer.pm, old/sql-ledger/SL/Menu.pm, + old/sql-ledger/SL/Num2text.pm, old/sql-ledger/SL/OE.pm, + old/sql-ledger/SL/PE.pm, old/sql-ledger/SL/RC.pm, + old/sql-ledger/SL/RP.pm, old/sql-ledger/SL/User.pm, + old/sql-ledger/bin/lynx/menu.pl, + old/sql-ledger/bin/mozilla/admin.pl, + old/sql-ledger/bin/mozilla/am.pl, + old/sql-ledger/bin/mozilla/ap.pl, + old/sql-ledger/bin/mozilla/ar.pl, + old/sql-ledger/bin/mozilla/arap.pl, + old/sql-ledger/bin/mozilla/ca.pl, + old/sql-ledger/bin/mozilla/cp.pl, + old/sql-ledger/bin/mozilla/ct.pl, + old/sql-ledger/bin/mozilla/gl.pl, + old/sql-ledger/bin/mozilla/ic.pl, + old/sql-ledger/bin/mozilla/io.pl, + old/sql-ledger/bin/mozilla/ir.pl, + old/sql-ledger/bin/mozilla/is.pl, + old/sql-ledger/bin/mozilla/login.pl, + old/sql-ledger/bin/mozilla/menu.pl, + old/sql-ledger/bin/mozilla/oe.pl, + old/sql-ledger/bin/mozilla/pe.pl, + old/sql-ledger/bin/mozilla/rc.pl, + old/sql-ledger/bin/mozilla/rp.pl, + old/sql-ledger/css/sql-ledger.css, old/sql-ledger/doc/COPYING, + old/sql-ledger/doc/README, old/sql-ledger/doc/UPGRADE-1.6-1.8, + old/sql-ledger/doc/UPGRADE-1.8-1.8.3, + old/sql-ledger/doc/UPGRADE-1.8.3-1.8.4, + old/sql-ledger/doc/UPGRADE-1.8.4-1.8.5, + old/sql-ledger/doc/UPGRADE-1.8.5-1.8.7, + old/sql-ledger/doc/UPGRADE-1.8.7-2.0.0, + old/sql-ledger/doc/UPGRADE-2.0-2.0.8, + old/sql-ledger/doc/copyright, old/sql-ledger/doc/faq.html, + old/sql-ledger/locale/br/COPYING, + old/sql-ledger/locale/br/LANGUAGE, + old/sql-ledger/locale/br/admin, old/sql-ledger/locale/br/all, + old/sql-ledger/locale/br/am, old/sql-ledger/locale/br/ap, + old/sql-ledger/locale/br/ar, old/sql-ledger/locale/br/arap, + old/sql-ledger/locale/br/ca, old/sql-ledger/locale/br/cp, + old/sql-ledger/locale/br/ct, old/sql-ledger/locale/br/gl, + old/sql-ledger/locale/br/ic, old/sql-ledger/locale/br/io, + old/sql-ledger/locale/br/ir, old/sql-ledger/locale/br/is, + old/sql-ledger/locale/br/login, old/sql-ledger/locale/br/menu, + old/sql-ledger/locale/br/oe, old/sql-ledger/locale/br/pe, + old/sql-ledger/locale/br/rc, old/sql-ledger/locale/br/rp, + old/sql-ledger/locale/cn/COPYING, + old/sql-ledger/locale/cn/LANGUAGE, + old/sql-ledger/locale/cn/admin, old/sql-ledger/locale/cn/all, + old/sql-ledger/locale/cn/am, old/sql-ledger/locale/cn/ap, + old/sql-ledger/locale/cn/ar, old/sql-ledger/locale/cn/arap, + old/sql-ledger/locale/cn/ca, old/sql-ledger/locale/cn/cp, + old/sql-ledger/locale/cn/ct, old/sql-ledger/locale/cn/gl, + old/sql-ledger/locale/cn/ic, old/sql-ledger/locale/cn/io, + old/sql-ledger/locale/cn/ir, old/sql-ledger/locale/cn/is, + old/sql-ledger/locale/cn/login, old/sql-ledger/locale/cn/menu, + old/sql-ledger/locale/cn/oe, old/sql-ledger/locale/cn/pe, + old/sql-ledger/locale/cn/rc, old/sql-ledger/locale/cn/rp, + old/sql-ledger/locale/ct/COPYING, + old/sql-ledger/locale/ct/LANGUAGE, + old/sql-ledger/locale/ct/admin, old/sql-ledger/locale/ct/all, + old/sql-ledger/locale/ct/am, old/sql-ledger/locale/ct/ap, + old/sql-ledger/locale/ct/ar, old/sql-ledger/locale/ct/arap, + old/sql-ledger/locale/ct/ca, old/sql-ledger/locale/ct/cp, + old/sql-ledger/locale/ct/ct, old/sql-ledger/locale/ct/gl, + old/sql-ledger/locale/ct/ic, old/sql-ledger/locale/ct/io, + old/sql-ledger/locale/ct/ir, old/sql-ledger/locale/ct/is, + old/sql-ledger/locale/ct/login, old/sql-ledger/locale/ct/menu, + old/sql-ledger/locale/ct/oe, old/sql-ledger/locale/ct/pe, + old/sql-ledger/locale/ct/rc, old/sql-ledger/locale/ct/rp, + old/sql-ledger/locale/cz/COPYING, + old/sql-ledger/locale/cz/LANGUAGE, + old/sql-ledger/locale/cz/admin, old/sql-ledger/locale/cz/all, + old/sql-ledger/locale/cz/am, old/sql-ledger/locale/cz/ap, + old/sql-ledger/locale/cz/ar, old/sql-ledger/locale/cz/arap, + old/sql-ledger/locale/cz/ca, old/sql-ledger/locale/cz/cp, + old/sql-ledger/locale/cz/ct, old/sql-ledger/locale/cz/gl, + old/sql-ledger/locale/cz/ic, old/sql-ledger/locale/cz/io, + old/sql-ledger/locale/cz/ir, old/sql-ledger/locale/cz/is, + old/sql-ledger/locale/cz/login, old/sql-ledger/locale/cz/menu, + old/sql-ledger/locale/cz/oe, old/sql-ledger/locale/cz/pe, + old/sql-ledger/locale/cz/rc, old/sql-ledger/locale/cz/rp, + old/sql-ledger/locale/de/COPYING, + old/sql-ledger/locale/de/LANGUAGE, + old/sql-ledger/locale/de/Num2text, + old/sql-ledger/locale/de/admin, + old/sql-ledger/locale/de/locales.pl, + old/sql-ledger/locale/de/all, old/sql-ledger/locale/de/am, + old/sql-ledger/locale/de/ap, old/sql-ledger/locale/de/ar, + old/sql-ledger/locale/de/arap, old/sql-ledger/locale/de/ca, + old/sql-ledger/locale/de/cp, old/sql-ledger/locale/de/ct, + old/sql-ledger/locale/de/gl, old/sql-ledger/locale/de/ic, + old/sql-ledger/locale/de/io, old/sql-ledger/locale/de/ir, + old/sql-ledger/locale/de/is, old/sql-ledger/locale/de/login, + old/sql-ledger/locale/de/menu, old/sql-ledger/locale/de/oe, + old/sql-ledger/locale/de/pe, old/sql-ledger/locale/de/rc, + old/sql-ledger/locale/de/rp, old/sql-ledger/locale/dk/COPYING, + old/sql-ledger/locale/dk/LANGUAGE, + old/sql-ledger/locale/dk/admin, old/sql-ledger/locale/dk/all, + old/sql-ledger/locale/dk/am, old/sql-ledger/locale/dk/ap, + old/sql-ledger/locale/dk/ar, old/sql-ledger/locale/dk/arap, + old/sql-ledger/locale/dk/ca, old/sql-ledger/locale/dk/cp, + old/sql-ledger/locale/dk/ct, old/sql-ledger/locale/dk/gl, + old/sql-ledger/locale/dk/ic, old/sql-ledger/locale/dk/io, + old/sql-ledger/locale/dk/ir, old/sql-ledger/locale/dk/is, + old/sql-ledger/locale/dk/login, old/sql-ledger/locale/dk/menu, + old/sql-ledger/locale/dk/oe, old/sql-ledger/locale/dk/pe, + old/sql-ledger/locale/dk/rc, old/sql-ledger/locale/dk/rp, + old/sql-ledger/locale/ee/COPYING, + old/sql-ledger/locale/ee/LANGUAGE, + old/sql-ledger/locale/ee/admin, old/sql-ledger/locale/ee/all, + old/sql-ledger/locale/ee/am, old/sql-ledger/locale/ee/ap, + old/sql-ledger/locale/ee/ar, old/sql-ledger/locale/ee/arap, + old/sql-ledger/locale/ee/ca, old/sql-ledger/locale/ee/cp, + old/sql-ledger/locale/ee/ct, old/sql-ledger/locale/ee/gl, + old/sql-ledger/locale/ee/ic, old/sql-ledger/locale/ee/io, + old/sql-ledger/locale/ee/ir, old/sql-ledger/locale/ee/is, + old/sql-ledger/locale/ee/login, old/sql-ledger/locale/ee/menu, + old/sql-ledger/locale/ee/oe, old/sql-ledger/locale/ee/pe, + old/sql-ledger/locale/ee/rc, old/sql-ledger/locale/ee/rp, + old/sql-ledger/locale/en_GB/COPYING, + old/sql-ledger/locale/en_GB/LANGUAGE, + old/sql-ledger/locale/en_GB/admin, + old/sql-ledger/locale/en_GB/all, old/sql-ledger/locale/en_GB/am, + old/sql-ledger/locale/en_GB/ap, old/sql-ledger/locale/en_GB/ar, + old/sql-ledger/locale/en_GB/arap, old/sql-ledger/locale/en_GB/bp, + old/sql-ledger/locale/en_GB/ca, old/sql-ledger/locale/en_GB/cp, + old/sql-ledger/locale/en_GB/ct, old/sql-ledger/locale/en_GB/gl: + Initial revision + +2004-11-13 04:44 ivan + + * sql-ledger/sql-ledger/: templates/Default-work_order.tex, + templates/Hungarian-purchase_order.html, + templates/Hungarian-purchase_order.tex, + templates/Hungarian-receipt.tex, + templates/Hungarian-sales_order.html, + templates/Hungarian-sales_order.tex, + templates/Hungarian-statement.html, + templates/Hungarian-statement.tex, templates/Danish-bin_list.tex, + templates/Danish-work_order.html, + templates/Danish-work_order.tex, + templates/Default-work_order.html, + templates/Dutch-work_order.html, templates/Dutch-work_order.tex, + templates/Estonian-pos_invoice.txt, + templates/French-pos_invoice.txt, + templates/Service-work_order.html, + templates/Service-work_order.tex, + templates/Estonian-work_order.html, + templates/Estonian-work_order.tex, + templates/French-work_order.html, + templates/French-work_order.tex, + templates/German-work_order.html, + templates/German-work_order.tex, + templates/Hungarian-work_order.html, + templates/Hungarian-work_order.tex, + templates/Italian-work_order.html, + templates/Italian-work_order.tex, + templates/Norwegian-work_order.html, + templates/Brazilian_Portuguese-bin_list.html, + templates/Brazilian_Portuguese-bin_list.tex, + templates/Brazilian_Portuguese-pick_list.html, + templates/Brazilian_Portuguese-pick_list.tex, + templates/Brazilian_Portuguese-pos_invoice.txt, + templates/Danish-pick_list.html, + templates/German-pos_invoice.txt, + templates/Italian-pos_invoice.txt, + templates/Norwegian-pos_invoice.txt, + templates/Norwegian-work_order.tex, + templates/Service-pos_invoice.txt, + templates/Spanish_A4-pos_invoice.txt, + templates/Spanish_A4-work_order.html, + templates/Spanish_A4-work_order.tex, + templates/Spanish_Letter-pos_invoice.txt, + templates/Spanish_Letter-work_order.html, + templates/Spanish_Letter-work_order.tex, + templates/Brazilian_Portuguese-request_quotation.html, + templates/Brazilian_Portuguese-request_quotation.tex, + templates/Brazilian_Portuguese-sales_quotation.html, + templates/Brazilian_Portuguese-sales_quotation.tex, + templates/Brazilian_Portuguese-work_order.html, + templates/Brazilian_Portuguese-work_order.tex, + templates/Danish-bin_list.html, templates/Danish-pick_list.tex, + templates/Danish-request_quotation.html, + templates/Danish-request_quotation.tex, + templates/Danish-sales_quotation.html, + templates/Danish-sales_quotation.tex, + templates/Dutch-bin_list.html, templates/Dutch-bin_list.tex, + templates/Dutch-pick_list.html, templates/Dutch-pick_list.tex, + templates/Dutch-request_quotation.html, + templates/Dutch-request_quotation.tex, + templates/Dutch-sales_quotation.html, + templates/Dutch-sales_quotation.tex, + templates/Estonian-bin_list.html, + templates/Estonian-bin_list.tex, + templates/Estonian-pick_list.html, + templates/Estonian-pick_list.tex, + templates/Estonian-request_quotation.html, + templates/Estonian-request_quotation.tex, + templates/French-bin_list.html, templates/French-bin_list.tex, + templates/French-pick_list.html, templates/French-pick_list.tex, + templates/French-request_quotation.html, + templates/French-request_quotation.tex, + templates/French-sales_quotation.html, + templates/French-sales_quotation.tex, + templates/German-bin_list.html, templates/German-bin_list.tex, + templates/German-pick_list.html, templates/German-pick_list.tex, + templates/German-request_quotation.html, + templates/German-request_quotation.tex, + templates/German-sales_quotation.html, + templates/German-sales_quotation.tex, + templates/Hungarian-bin_list.html, + templates/Hungarian-bin_list.tex, + templates/Hungarian-pick_list.html, + templates/Hungarian-pick_list.tex, + templates/Hungarian-request_quotation.html, + templates/Hungarian-request_quotation.tex, + templates/Hungarian-sales_quotation.html, + templates/Hungarian-sales_quotation.tex, + templates/Italian-bin_list.html, templates/Italian-bin_list.tex, + templates/Italian-pick_list.html, + templates/Italian-pick_list.tex, + templates/Italian-request_quotation.html, + templates/Italian-request_quotation.tex, + templates/Italian-sales_quotation.html, + templates/Italian-sales_quotation.tex, + templates/Norwegian-bin_list.html, + templates/Norwegian-bin_list.tex, + templates/Norwegian-pick_list.html, + templates/Norwegian-pick_list.tex, + templates/Norwegian-request_quotation.html, + templates/Norwegian-request_quotation.tex, + templates/Norwegian-sales_quotation.html, + templates/Norwegian-sales_quotation.tex, + templates/Service-bin_list.html, templates/Service-bin_list.tex, + templates/Service-pick_list.html, + templates/Service-pick_list.tex, + templates/Service-request_quotation.html, + templates/Service-request_quotation.tex, + templates/Service-sales_quotation.html, + templates/Service-sales_quotation.tex, + templates/Spanish_A4-bin_list.html, + templates/Spanish_A4-bin_list.tex, + templates/Spanish_A4-pick_list.html, + templates/Spanish_A4-pick_list.tex, + templates/Spanish_A4-request_quotation.html, + templates/Spanish_A4-request_quotation.tex, + templates/Spanish_A4-sales_quotation.html, + templates/Spanish_A4-sales_quotation.tex, + templates/Spanish_Letter-bin_list.html, + templates/Spanish_Letter-bin_list.tex, + templates/Spanish_Letter-pick_list.html, + templates/Spanish_Letter-pick_list.tex, + templates/Spanish_Letter-request_quotation.html, + templates/Spanish_Letter-request_quotation.tex, + templates/Spanish_Letter-sales_quotation.html, + templates/Spanish_Letter-sales_quotation.tex, + templates/Brazilian_Portuguese-ap_transaction.html, + templates/Brazilian_Portuguese-ap_transaction.tex, + templates/Brazilian_Portuguese-ar_transaction.html, + templates/Brazilian_Portuguese-ar_transaction.tex, + templates/Danish-ap_transaction.html, + templates/Danish-ap_transaction.tex, + templates/Danish-ar_transaction.html, + templates/Danish-ar_transaction.tex, + templates/Default-ap_transaction.html, + templates/Default-ap_transaction.tex, + templates/Default-ar_transaction.html, + templates/Default-ar_transaction.tex, + templates/Dutch-ap_transaction.html, + templates/Dutch-ap_transaction.tex, + templates/Dutch-ar_transaction.html, + templates/Dutch-ar_transaction.tex, + templates/Estonian-ap_transaction.html, + templates/Estonian-ap_transaction.tex, + templates/Estonian-ar_transaction.html, + templates/Estonian-ar_transaction.tex, + templates/French-ap_transaction.html, + templates/French-ap_transaction.tex, + templates/French-ar_transaction.html, + templates/French-ar_transaction.tex, + templates/German-ap_transaction.html, + templates/German-ap_transaction.tex, + templates/German-ar_transaction.html, + templates/German-ar_transaction.tex, + templates/Hungarian-ap_transaction.html, + templates/Hungarian-ap_transaction.tex, + templates/Hungarian-ar_transaction.html, + templates/Hungarian-ar_transaction.tex, + templates/Italian-ap_transaction.html, + templates/Italian-ap_transaction.tex, + templates/Italian-ar_transaction.html, + templates/Italian-ar_transaction.tex, + templates/Norwegian-ap_transaction.html, + templates/Norwegian-ap_transaction.tex, + templates/Norwegian-ar_transaction.html, + templates/Norwegian-ar_transaction.tex, + templates/Service-ap_transaction.html, + templates/Service-ap_transaction.tex, + templates/Service-ar_transaction.html, + templates/Service-ar_transaction.tex, + templates/Spanish_A4-ap_transaction.html, + templates/Spanish_A4-ap_transaction.tex, + templates/Spanish_A4-ar_transaction.html, + templates/Spanish_A4-ar_transaction.tex, + templates/Spanish_Letter-ap_transaction.html, + templates/Spanish_Letter-ap_transaction.tex, css/sql-ledger.css, + templates/Spanish_Letter-ar_transaction.html, + templates/Spanish_Letter-ar_transaction.tex, + users/sql-ledger.eps, users/sql-ledger.png, SL/AP.pm, SL/AR.pm, + SL/Form.pm, SL/User.pm, SL/GL.pm, SL/CT.pm, SL/IC.pm, SL/IR.pm, + SL/IS.pm, SL/AM.pm, SL/CA.pm, SL/RP.pm, SL/Menu.pm, + SL/Inifile.pm, SL/Mailer.pm, SL/OE.pm, SL/Num2text.pm, SL/PE.pm, + SL/BP.pm, SL/HR.pm, SL/CP.pm, SL/OP.pm, SL/RC.pm, + locale/de/admin, locale/de/am, locale/de/ap, locale/de/ar, + locale/de/arap, locale/de/bp, locale/de/ca, locale/de/cp, + locale/de/ct, locale/de/locales.pl, locale/de/gl, locale/de/hr, + locale/de/ic, locale/de/io, locale/de/COPYING, + locale/de/LANGUAGE, locale/de/ir, locale/de/is, locale/de/login, + locale/de/menu, locale/de/oe, locale/de/pe, locale/de/pos, + locale/de/ps, locale/de/rc, locale/de/Num2text, + locale/de/arapprn, locale/de/pw, locale/de/rp, locale/fr/admin, + locale/fr/am, locale/fr/io, locale/fr/all, locale/fr/ap, + locale/fr/ar, locale/fr/ca, locale/fr/ct, locale/fr/gl, + locale/fr/arap, locale/fr/ic, locale/fr/ir, locale/fr/is, + locale/fr/rp, locale/fr/COPYING, locale/fr/LANGUAGE, + locale/fr/login, locale/fr/menu, locale/fr/oe, locale/fr/pe, + locale/fr/bp, locale/fr/cp, locale/fr/pos, locale/fr/ps, + locale/fr/rc, locale/co/COPYING, locale/co/LANGUAGE, + locale/co/Num2text, locale/fr/Num2text, locale/fr/arapprn, + locale/fr/hr, locale/fr/pw, locale/co/admin, locale/co/all, + locale/co/am, locale/co/ap, locale/co/ar, locale/co/ca, + locale/co/ct, locale/co/gl, locale/co/ic, locale/co/io, + locale/co/ir, locale/co/login, locale/co/menu, locale/co/is, + locale/co/oe, locale/co/rp, locale/co/arap, locale/co/bp, + locale/co/cp, locale/co/pe, locale/co/pos, locale/co/rc, + locale/co/arapprn, locale/co/hr, locale/co/ps, locale/co/pw, + locale/dk/admin, locale/dk/ap, locale/dk/ar, locale/dk/ca, + locale/dk/menu, locale/dk/ct, locale/dk/gl, locale/dk/ic, + locale/dk/ir, locale/dk/is, locale/dk/login, locale/dk/LANGUAGE, + locale/dk/am, locale/dk/io, locale/dk/rp, locale/dk/COPYING, + locale/dk/arap, locale/dk/bp, locale/dk/cp, locale/dk/oe, + locale/dk/pe, locale/dk/rc, locale/dk/pos, locale/dk/hr, + locale/dk/ps, locale/br/ar, locale/dk/all, locale/dk/arapprn, + locale/dk/pw, locale/br/admin, locale/br/login, locale/br/all, + locale/br/am, locale/br/ct, locale/br/gl, locale/br/ic, + locale/br/ir, locale/br/is, locale/br/ap, locale/br/ca, + locale/br/menu, locale/br/rp, locale/br/COPYING, + locale/br/LANGUAGE, locale/br/arap, locale/br/cp, locale/br/io, + locale/br/oe, locale/br/pe, locale/br/bp, locale/br/pos, + locale/br/ps, locale/br/rc, locale/br/arapprn, locale/br/hr, + locale/br/pw, locale/it/admin, locale/it/ap, locale/it/ar, + locale/it/ca, locale/it/ct, locale/it/gl, locale/it/menu, + locale/it/ic, locale/it/ir, locale/it/is, locale/it/login, + locale/it/rp, locale/it/all, locale/it/am, locale/it/io, + locale/it/COPYING, locale/it/LANGUAGE, locale/it/Num2text, + locale/it/arap, locale/it/bp, locale/it/cp, locale/it/oe, + locale/it/pe, locale/it/rc, locale/it/pos, locale/it/qe, + locale/ct/COPYING, locale/ct/LANGUAGE, locale/it/arapprn, + locale/it/hr, locale/it/ps, locale/it/pw, locale/ct/all, + locale/ct/admin, locale/ct/am, locale/ct/ap, locale/ct/ar, + locale/ct/ca, locale/ct/ct, locale/ct/gl, locale/ct/ic, + locale/ct/io, locale/ct/ir, locale/ct/login, locale/ct/is, + locale/ct/menu, locale/ct/rp, locale/ct/arap, locale/ct/arapprn, + locale/ct/bp, locale/ct/cp, locale/ct/hr, locale/ct/oe, + locale/ct/pe, locale/ct/pos, locale/ct/ps, locale/ct/pw, + locale/ct/rc, locale/ee/admin, locale/ee/login, locale/ee/all, + locale/ee/ar, locale/ee/ct, locale/ee/gl, locale/ee/ic, + locale/ee/ir, locale/ee/am, locale/ee/ap, locale/ee/ca, + locale/ee/is, locale/ee/menu, locale/ee/rp, locale/ee/COPYING, + locale/ee/LANGUAGE, locale/ee/arap, locale/ee/io, locale/ee/oe, + locale/ee/pe, locale/ee/cp, locale/ee/rc, locale/ee/Num2text, + locale/ee/arapprn, locale/ee/bp, locale/ee/hr, locale/ee/pos, + locale/ee/ps, locale/ee/pw, locale/nl/admin, locale/nl/all, + locale/nl/am, locale/nl/ap, locale/nl/ar, locale/nl/ca, + locale/nl/ct, locale/nl/gl, locale/nl/ic, locale/nl/ir, + locale/nl/io, locale/nl/is, locale/nl/login, locale/nl/menu, + locale/nl/oe, locale/nl/rp, locale/nl/COPYING, + locale/nl/LANGUAGE, locale/nl/Num2text, locale/nl/arap, + locale/nl/bp, locale/nl/cp, locale/nl/pe, locale/nl/pos, + locale/nl/rc, locale/nl/arapprn, locale/nl/hr, locale/nl/ps, + locale/nl/pw, locale/tr/COPYING, locale/tr/admin, locale/tr/all, + locale/tr/am, locale/tr/ap, locale/tr/ar, locale/tr/ca, + locale/tr/ct, locale/tr/gl, locale/tr/ic, locale/tr/LANGUAGE, + locale/tr/arap, locale/tr/io, locale/tr/ir, locale/tr/is, + locale/tr/login, locale/tr/menu, locale/tr/oe, locale/tr/pe, + locale/tr/rp, locale/tr/arapprn, locale/tr/bp, locale/tr/cp, + locale/tr/hr, locale/tr/pos, locale/tr/ps, locale/tr/pw, + locale/tr/rc, locale/ve/COPYING, locale/ve/admin, locale/ve/all, + locale/ve/login, locale/ve/am, locale/ve/ar, locale/ve/ap, + locale/ve/ct, locale/ve/gl, locale/ve/ic, locale/ve/ir, + locale/ve/ca, locale/ve/is, locale/ve/rp, locale/ve/LANGUAGE, + locale/ve/arap, locale/ve/cp, locale/ve/io, locale/ve/menu, + locale/ve/oe, locale/ve/pe, locale/ve/arapprn, locale/ve/bp, + locale/ve/hr, locale/ve/pos, locale/ve/ps, locale/ve/pw, + locale/ve/rc, locale/pa/admin, locale/pa/all, locale/pa/am, + locale/pa/ap, locale/pa/ar, locale/pa/ca, locale/pa/ct, + locale/pa/gl, locale/pa/ic, locale/pa/ir, locale/pa/is, + locale/pa/login, locale/pa/menu, locale/pa/COPYING, + locale/pa/LANGUAGE, locale/pa/arap, locale/pa/io, locale/pa/oe, + locale/pa/pe, locale/pa/rp, locale/pa/arapprn, locale/pa/bp, + locale/pa/cp, locale/pa/hr, locale/pa/pos, locale/pa/ps, + locale/pa/pw, locale/pa/rc, locale/cz/all, locale/cz/admin, + locale/cz/am, locale/cz/ap, locale/cz/ar, locale/cz/ca, + locale/cz/ct, locale/cz/gl, locale/cz/ic, locale/cz/ir, + locale/cz/COPYING, locale/cz/LANGUAGE, locale/cz/arap, + locale/cz/io, locale/cz/is, locale/cz/login, locale/cz/menu, + locale/cz/oe, locale/cz/rp, locale/cz/arapprn, locale/cz/bp, + locale/cz/cp, locale/cz/hr, locale/cz/pe, locale/cz/pos, + locale/cz/ps, locale/cz/pw, locale/cz/rc, locale/pt/admin, + locale/pt/all, locale/pt/am, locale/pt/ap, locale/pt/ar, + locale/pt/ca, locale/pt/ct, locale/pt/gl, locale/pt/ic, + locale/pt/ir, locale/pt/is, locale/pt/login, locale/pt/COPYING, + locale/pt/LANGUAGE, locale/pt/arap, locale/pt/io, locale/pt/menu, + locale/pt/oe, locale/pt/rp, locale/pt/bp, locale/pt/cp, + locale/pt/pe, locale/pt/pos, locale/pt/rc, locale/ec/admin, + locale/pt/arapprn, locale/pt/hr, locale/pt/ps, locale/pt/pw, + locale/ec/all, locale/ec/am, locale/ec/ap, locale/ec/COPYING, + locale/ec/ar, locale/ec/arap, locale/ec/bp, locale/ec/ca, + locale/ec/cp, locale/ec/ct, locale/ec/gl, locale/ec/hr, + locale/ec/ic, locale/ec/LANGUAGE, locale/ec/io, locale/ec/ir, + locale/ec/is, locale/ec/login, locale/ec/Num2text, + locale/ec/menu, locale/ec/oe, locale/ec/pe, locale/ec/pos, + locale/ec/arapprn, locale/ec/ps, locale/ec/pw, locale/ec/rc, + locale/ec/rp, locale/pl/admin, locale/pl/all, locale/pl/am, + locale/pl/ap, locale/pl/ar, locale/pl/ca, locale/pl/ct, + locale/pl/gl, locale/pl/ic, locale/pl/ir, locale/pl/COPYING, + locale/pl/is, locale/pl/login, locale/pl/menu, locale/pl/rp, + locale/pl/LANGUAGE, locale/pl/arap, locale/pl/cp, locale/pl/io, + locale/pl/oe, locale/pl/pe, locale/pl/bp, locale/pl/pos, + locale/pl/rc, locale/mx/COPYING, locale/pl/arapprn, locale/pl/hr, + locale/pl/ps, locale/pl/pw, locale/mx/all, locale/mx/admin, + locale/mx/am, locale/mx/ap, locale/mx/ar, locale/mx/ca, + locale/mx/ct, locale/mx/gl, locale/mx/ic, locale/mx/ir, + locale/mx/is, locale/mx/login, locale/mx/menu, locale/mx/rp, + locale/mx/LANGUAGE, locale/mx/arap, locale/mx/cp, locale/mx/io, + locale/mx/oe, locale/mx/pe, locale/mx/bp, locale/mx/pos, + locale/mx/ps, locale/mx/rc, locale/fi/COPYING, + locale/fi/LANGUAGE, locale/mx/arapprn, locale/mx/hr, + locale/mx/pw, locale/fi/admin, locale/fi/all, locale/fi/am, + locale/fi/ap, locale/fi/ar, locale/fi/ca, locale/fi/ct, + locale/fi/gl, locale/fi/ic, locale/fi/ir, locale/fi/io, + locale/fi/login, locale/fi/menu, locale/fi/rp, locale/fi/arap, + locale/fi/bp, locale/fi/cp, locale/fi/is, locale/fi/oe, + locale/fi/pe, locale/fi/pos, locale/fi/rc, locale/fi/arapprn, + locale/fi/hr, locale/fi/ps, locale/fi/pw, locale/ru/COPYING, + locale/ru/LANGUAGE, locale/ru/all, locale/ru/admin, locale/ru/am, + locale/ru/ap, locale/ru/ar, locale/ru/ca, locale/ru/ct, + locale/ru/gl, locale/ru/ic, locale/ru/io, locale/ru/ir, + locale/ru/is, locale/ru/login, locale/ru/menu, locale/ru/rp: + Initial revision + +2004-11-13 04:41 ivan + + * sql-ledger/: sql-ledger-2.0.8.tar.gz, sql-ledger-2.4.4.tar.gz, + sql-ledger/VERSION, sql-ledger/am.pl, sql-ledger/favicon.ico, + sql-ledger/index.html, sql-ledger/login.pl, sql-ledger/menu.ini, + sql-ledger/setup.pl, sql-ledger/sql-ledger.conf.default, + sql-ledger/sql-ledger.gif, sql-ledger/sql-ledger.png, + sql-ledger/bin/mozilla/admin.pl, sql-ledger/bin/mozilla/am.pl, + sql-ledger/bin/mozilla/ap.pl, sql-ledger/bin/mozilla/ar.pl, + sql-ledger/bin/mozilla/ca.pl, sql-ledger/bin/mozilla/ct.pl, + sql-ledger/bin/mozilla/gl.pl, sql-ledger/bin/mozilla/ic.pl, + sql-ledger/bin/mozilla/ir.pl, sql-ledger/bin/mozilla/io.pl, + sql-ledger/bin/mozilla/login.pl, sql-ledger/bin/mozilla/menu.pl, + sql-ledger/bin/mozilla/rp.pl, sql-ledger/bin/mozilla/is.pl, + sql-ledger/bin/mozilla/oe.pl, sql-ledger/bin/mozilla/arap.pl, + sql-ledger/bin/mozilla/pe.pl, sql-ledger/bin/mozilla/bp.pl, + sql-ledger/bin/mozilla/cp.pl, sql-ledger/bin/mozilla/rc.pl, + sql-ledger/bin/mozilla/pos.pl, sql-ledger/bin/mozilla/ps.pl, + sql-ledger/bin/lynx/menu.pl, sql-ledger/bin/mozilla/arapprn.pl, + sql-ledger/bin/mozilla/hr.pl, sql-ledger/bin/mozilla/pw.pl, + sql-ledger/bin/js/menu.pl, sql-ledger/doc/COPYING, + sql-ledger/doc/README, sql-ledger/doc/COPYRIGHT, + sql-ledger/doc/README.DB2, sql-ledger/doc/UPGRADE-1.6-1.8, + sql-ledger/doc/UPGRADE-1.8-1.8.3, + sql-ledger/doc/UPGRADE-1.8.3-1.8.4, + sql-ledger/doc/UPGRADE-1.8.4-1.8.5, + sql-ledger/doc/UPGRADE-1.8.5-1.8.7, + sql-ledger/doc/UPGRADE-1.8.7-2.0.0, + sql-ledger/doc/UPGRADE-2.0-2.0.8, + sql-ledger/doc/UPGRADE-2.0.8-2.0.9, + sql-ledger/doc/UPGRADE-2.0.9-2.2.0, + sql-ledger/doc/UPGRADE-2.2.0-2.2.7, sql-ledger/doc/faq.html, + sql-ledger/doc/UPGRADE-2.2.7-2.4.0, + sql-ledger/doc/UPGRADE-2.4.0-2.4.1, + sql-ledger/doc/UPGRADE-2.4.1-2.4.2, + sql-ledger/doc/UPGRADE-2.4.2-2.4.3, + sql-ledger/doc/UPGRADE-2.4.3-2.4.4, + sql-ledger/sql/Default-chart.sql, + sql-ledger/sql/Oracle-tables.sql, + sql-ledger/sql/France-chart.sql, + sql-ledger/sql/Pg-upgrade-1.6.0-1.8.0.sql, + sql-ledger/sql/Dutch_Default-chart.sql, + sql-ledger/sql/Poland-chart.sql, + sql-ledger/sql/Danish_Default-chart.sql, + sql-ledger/sql/Italy-gifi.sql, + sql-ledger/sql/Czech-Republic-chart.sql, + sql-ledger/sql/Simplified-Chinese_Default-chart.sql, + sql-ledger/sql/Traditional-Chinese_Default-chart.sql, + sql-ledger/sql/Oracle-indices.sql, sql-ledger/sql/Pg-indices.sql, + sql-ledger/sql/Austria-chart.sql, + sql-ledger/sql/Pg-upgrade-1.2.6-1.2.7.sql, + sql-ledger/sql/Pg-upgrade-1.2.7-1.4.0.sql, + sql-ledger/sql/Pg-upgrade-1.4.0-1.6.0.sql, + sql-ledger/sql/Pg-upgrade-1.8.0-1.8.4.sql, + sql-ledger/sql/US_General-chart.sql, + sql-ledger/sql/Dutch_Standard-chart.sql, + sql-ledger/sql/Oracle-upgrade-1.8.0-1.8.4.sql, + sql-ledger/sql/Swiss-German-gifi.sql, + sql-ledger/sql/Canada-English_General-chart.sql, + sql-ledger/sql/German-Sample-gifi.sql, + sql-ledger/sql/Pg-upgrade-1.8.4-1.8.5.sql, + sql-ledger/sql/Austria-gifi.sql, + sql-ledger/sql/Pg-upgrade-2.3.0-2.3.1.sql, + sql-ledger/sql/DB2-create.sql, sql-ledger/sql/Swedish-chart.sql, + sql-ledger/sql/German-Sample-chart.sql, + sql-ledger/sql/Oracle-upgrade-1.8.4-1.8.5.sql, + sql-ledger/sql/Swiss-German-chart.sql, + sql-ledger/sql/Germany-SKR03-gifi.sql, + sql-ledger/sql/Germany-SKR03-chart.sql, + sql-ledger/sql/Germany-DATEV-SKR03-gifi.sql, + sql-ledger/sql/Pg-upgrade-1.8.5-2.0.0.sql, + sql-ledger/sql/Germany-DATEV-SKR03-chart.sql, + sql-ledger/sql/Oracle-upgrade-1.8.5-2.0.0.sql, + sql-ledger/sql/Oracle-upgrade-2.0.8-2.2.0.sql, + sql-ledger/sql/Pg-upgrade-2.0.8-2.2.0.sql, + sql-ledger/sql/Brazil_General-chart.sql, + sql-ledger/sql/Hungary-chart.sql, + sql-ledger/sql/Italy_General-chart.sql, + sql-ledger/sql/Pg-upgrade-2.2.0-2.3.0.sql, + sql-ledger/sql/Norwegian_Default-chart.sql, + sql-ledger/sql/Pg-upgrade-2.0.0-2.0.8.sql, + sql-ledger/sql/Belgium-chart.sql, + sql-ledger/sql/Belgium-gifi.sql, sql-ledger/sql/Hungary-gifi.sql, + sql-ledger/sql/Pg-upgrade-2.3.1-2.3.3.sql, + sql-ledger/sql/Canada-English-gifi.sql, + sql-ledger/sql/Italy_cc2424-chart.sql, + sql-ledger/sql/Pg-upgrade-2.3.3-2.3.4.sql, + sql-ledger/sql/Pg-upgrade-2.3.4-2.3.5.sql, + sql-ledger/sql/Pg-upgrade-2.3.5-2.3.6.sql, + sql-ledger/sql/Spain-ISO-chart.sql, + sql-ledger/sql/Spain-UTF8-chart.sql, + sql-ledger/sql/Canada-French-gifi.sql, + sql-ledger/sql/DB2-set.sql, sql-ledger/sql/DB2-indices.sql, + sql-ledger/sql/DB2-remove.sql, sql-ledger/sql/DB2-tables.sql, + sql-ledger/sql/DB2-sql-ledger.order, + sql-ledger/sql/Latvia-chart.sql, + sql-ledger/sql/Oracle-upgrade-2.0.0-2.0.8.sql, + sql-ledger/sql/Pg-upgrade-2.3.6-2.3.7.sql, + sql-ledger/sql/NAICS.sql, + sql-ledger/sql/Pg-upgrade-2.3.7-2.3.8.sql, + sql-ledger/sql/Pg-upgrade-2.3.8-2.3.9.sql, + sql-ledger/sql/Colombia-PUC-chart.sql, + sql-ledger/sql/Colombia-PUC-gifi.sql, + sql-ledger/sql/Pg-functions.sql, sql-ledger/sql/Pg-tables.sql, + sql-ledger/sql/Egypt-chart.sql, + sql-ledger/sql/US_Manufacturing-chart.sql, + sql-ledger/sql/US_Service_Company-chart.sql, + sql-ledger/sql/Pg-upgrade-2.3.9-2.4.2.sql, + sql-ledger/sql/Pg-upgrade-2.4.2-2.4.3.sql, + sql-ledger/sql/Pg-upgrade-2.4.3-2.4.4.sql, + sql-ledger/sql/Simplified-Chinese_Default-UTF8-chart.sql, + sql-ledger/sql/Traditional-Chinese_Default-UTF8-chart.sql, + sql-ledger/templates/Danish-invoice.html, + sql-ledger/templates/Default-invoice.html, + sql-ledger/templates/Service-income_statement.html, + sql-ledger/templates/Service-invoice.html, + sql-ledger/templates/Service-packing_list.tex, + sql-ledger/templates/Service-purchase_order.tex, + sql-ledger/templates/Spanish_A4-invoice.html, + sql-ledger/templates/Spanish_A4-packing_list.html, + sql-ledger/templates/Spanish_A4-sales_order.html, + sql-ledger/templates/Danish-balance_sheet.html, + sql-ledger/templates/Danish-income_statement.html, + sql-ledger/templates/Danish-invoice.tex, + sql-ledger/templates/Default-income_statement.html, + sql-ledger/templates/Default-pos_invoice.txt, + sql-ledger/templates/French-invoice.html, + sql-ledger/templates/Spanish_A4-invoice.tex, + sql-ledger/templates/Spanish_A4-packing_list.tex, + sql-ledger/templates/Spanish_A4-purchase_order.tex, + sql-ledger/templates/Danish-packing_list.tex, + sql-ledger/templates/Default-balance_sheet.html, + sql-ledger/templates/French-packing_list.html, + sql-ledger/templates/Service-invoice.tex, + sql-ledger/templates/Service-sales_order.tex, + sql-ledger/templates/Spanish_A4-sales_order.tex, + sql-ledger/templates/Spanish_Letter-balance_sheet.html, + sql-ledger/templates/Spanish_Letter-income_statement.html, + sql-ledger/templates/Spanish_Letter-invoice.html, + sql-ledger/templates/Spanish_Letter-invoice.tex, + sql-ledger/templates/Spanish_Letter-packing_list.html, + sql-ledger/templates/French-balance_sheet.html, + sql-ledger/templates/French-income_statement.html, + sql-ledger/templates/Spanish_A4-balance_sheet.html, + sql-ledger/templates/Spanish_Letter-packing_list.tex, + sql-ledger/templates/Spanish_Letter-purchase_order.html, + sql-ledger/templates/Spanish_Letter-purchase_order.tex, + sql-ledger/templates/Spanish_Letter-sales_order.html, + sql-ledger/templates/Spanish_Letter-sales_order.tex, + sql-ledger/templates/Danish-packing_list.html, + sql-ledger/templates/Danish-purchase_order.html, + sql-ledger/templates/Danish-purchase_order.tex, + sql-ledger/templates/Danish-sales_order.html, + sql-ledger/templates/Danish-sales_order.tex, + sql-ledger/templates/Estonian-balance_sheet.html, + sql-ledger/templates/Estonian-income_statement.html, + sql-ledger/templates/Estonian-invoice.html, + sql-ledger/templates/Service-balance_sheet.html, + sql-ledger/templates/Service-packing_list.html, + sql-ledger/templates/Spanish_A4-income_statement.html, + sql-ledger/templates/Spanish_A4-purchase_order.html, + sql-ledger/templates/Default-packing_list.html, + sql-ledger/templates/Default-sales_order.html, + sql-ledger/templates/Estonian-invoice.tex, + sql-ledger/templates/Estonian-packing_list.html, + sql-ledger/templates/Estonian-packing_list.tex, + sql-ledger/templates/Estonian-purchase_order.html, + sql-ledger/templates/Service-purchase_order.html, + sql-ledger/templates/Default-purchase_order.html, + sql-ledger/templates/Dutch-balance_sheet.html, + sql-ledger/templates/Dutch-income_statement.html, + sql-ledger/templates/Dutch-invoice.html, + sql-ledger/templates/Estonian-purchase_order.tex, + sql-ledger/templates/Estonian-sales_order.html, + sql-ledger/templates/Estonian-sales_order.tex, + sql-ledger/templates/Service-sales_order.html, + sql-ledger/templates/Dutch-invoice.tex, + sql-ledger/templates/Dutch-packing_list.html, + sql-ledger/templates/Dutch-packing_list.tex, + sql-ledger/templates/Dutch-purchase_order.html, + sql-ledger/templates/Dutch-purchase_order.tex, + sql-ledger/templates/Dutch-sales_order.html, + sql-ledger/templates/Dutch-sales_order.tex, + sql-ledger/templates/French-invoice.tex, + sql-ledger/templates/French-packing_list.tex, + sql-ledger/templates/French-purchase_order.tex, + sql-ledger/templates/German-packing_list.html, + sql-ledger/templates/Default-invoice.tex, + sql-ledger/templates/Default-packing_list.tex, + sql-ledger/templates/Default-purchase_order.tex, + sql-ledger/templates/French-purchase_order.html, + sql-ledger/templates/French-sales_order.html, + sql-ledger/templates/French-sales_order.tex, + sql-ledger/templates/Default-sales_order.tex, + sql-ledger/templates/German-balance_sheet.html, + sql-ledger/templates/German-income_statement.html, + sql-ledger/templates/German-invoice.html, + sql-ledger/templates/German-invoice.tex, + sql-ledger/templates/German-packing_list.tex, + sql-ledger/templates/German-purchase_order.html, + sql-ledger/templates/German-purchase_order.tex, + sql-ledger/templates/German-sales_order.html, + sql-ledger/templates/Brazilian_Portuguese-check.tex, + sql-ledger/templates/Danish-check.tex, + sql-ledger/templates/Danish-receipt.tex, + sql-ledger/templates/Default-check.tex, + sql-ledger/templates/Default-receipt.tex, + sql-ledger/templates/Dutch-check.tex, + sql-ledger/templates/Dutch-receipt.tex, + sql-ledger/templates/Estonian-check.tex, + sql-ledger/templates/French-receipt.tex, + sql-ledger/templates/German-check.tex, + sql-ledger/templates/German-receipt.tex, + sql-ledger/templates/German-sales_order.tex, + sql-ledger/templates/Norwegian-balance_sheet.html, + sql-ledger/templates/Service-check.tex, + sql-ledger/templates/Service-receipt.tex, + sql-ledger/templates/Spanish_A4-check.tex, + sql-ledger/templates/Spanish_A4-receipt.tex, + sql-ledger/templates/Spanish_Letter-check.tex, + sql-ledger/templates/Spanish_Letter-receipt.tex, + sql-ledger/templates/Brazilian_Portuguese-balance_sheet.html, + sql-ledger/templates/Danish-statement.html, + sql-ledger/templates/Danish-statement.tex, + sql-ledger/templates/Default-statement.html, + sql-ledger/templates/Default-statement.tex, + sql-ledger/templates/Dutch-statement.html, + sql-ledger/templates/Dutch-statement.tex, + sql-ledger/templates/Estonian-statement.html, + sql-ledger/templates/Estonian-statement.tex, + sql-ledger/templates/French-statement.html, + sql-ledger/templates/French-statement.tex, + sql-ledger/templates/German-statement.html, + sql-ledger/templates/German-statement.tex, + sql-ledger/templates/Brazilian_Portuguese-income_statement.html, + sql-ledger/templates/Dutch-pos_invoice.txt, + sql-ledger/templates/Estonian-receipt.tex, + sql-ledger/templates/French-check.tex, + sql-ledger/templates/Service-statement.html, + sql-ledger/templates/Service-statement.tex, + sql-ledger/templates/Spanish_A4-statement.html, + sql-ledger/templates/Spanish_A4-statement.tex, + sql-ledger/templates/Spanish_Letter-statement.html, + sql-ledger/templates/Spanish_Letter-statement.tex, + sql-ledger/templates/Brazilian_Portuguese-invoice.html, + sql-ledger/templates/Brazilian_Portuguese-invoice.tex, + sql-ledger/templates/Brazilian_Portuguese-packing_list.html, + sql-ledger/templates/Brazilian_Portuguese-packing_list.tex, + sql-ledger/templates/Brazilian_Portuguese-purchase_order.html, + sql-ledger/templates/Brazilian_Portuguese-purchase_order.tex, + sql-ledger/templates/Brazilian_Portuguese-receipt.tex, + sql-ledger/templates/Brazilian_Portuguese-sales_order.html, + sql-ledger/templates/Brazilian_Portuguese-sales_order.tex, + sql-ledger/templates/Brazilian_Portuguese-statement.html, + sql-ledger/templates/Brazilian_Portuguese-statement.tex, + sql-ledger/templates/Danish-pos_invoice.txt, + sql-ledger/templates/Norwegian-check.tex, + sql-ledger/templates/Norwegian-income_statement.html, + sql-ledger/templates/Norwegian-invoice.html, + sql-ledger/templates/Norwegian-invoice.tex, + sql-ledger/templates/Norwegian-packing_list.html, + sql-ledger/templates/Norwegian-packing_list.tex, + sql-ledger/templates/Italian-balance_sheet.html, + sql-ledger/templates/Italian-check.tex, + sql-ledger/templates/Italian-income_statement.html, + sql-ledger/templates/Norwegian-purchase_order.html, + sql-ledger/templates/Norwegian-purchase_order.tex, + sql-ledger/templates/Norwegian-receipt.tex, + sql-ledger/templates/Norwegian-sales_order.html, + sql-ledger/templates/Norwegian-sales_order.tex, + sql-ledger/templates/Norwegian-statement.html, + sql-ledger/templates/Norwegian-statement.tex, + sql-ledger/templates/Italian-invoice.html, + sql-ledger/templates/Italian-invoice.tex, + sql-ledger/templates/Italian-packing_list.html, + sql-ledger/templates/Italian-packing_list.tex, + sql-ledger/templates/Italian-purchase_order.html, + sql-ledger/templates/Italian-purchase_order.tex, + sql-ledger/templates/Italian-receipt.tex, + sql-ledger/templates/Italian-sales_order.html, + sql-ledger/templates/Italian-sales_order.tex, + sql-ledger/templates/Italian-statement.html, + sql-ledger/templates/Default-bin_list.html, + sql-ledger/templates/Default-bin_list.tex, + sql-ledger/templates/Default-pick_list.html, + sql-ledger/templates/Default-pick_list.tex, + sql-ledger/templates/Default-request_quotation.html, + sql-ledger/templates/Default-request_quotation.tex, + sql-ledger/templates/Hungarian-balance_sheet.html, + sql-ledger/templates/Italian-statement.tex, + sql-ledger/templates/Default-sales_quotation.html, + sql-ledger/templates/Default-sales_quotation.tex, + sql-ledger/templates/Hungarian-check.tex, + sql-ledger/templates/Hungarian-income_statement.html, + sql-ledger/templates/Hungarian-invoice.html, + sql-ledger/templates/Hungarian-invoice.tex, + sql-ledger/templates/Hungarian-packing_list.html, + sql-ledger/templates/Hungarian-packing_list.tex, + sql-ledger/templates/Hungarian-pos_invoice.txt: Initial revision + 2004-11-12 21:37 ivan * FS/FS/svc_acct.pm: oops, that's better @@ -19443,6 +23276,18 @@ lib/t/data/rt-send-cc, lib/RT/I18N/hu.po, lib/RT/I18N/da.po: Initial revision +2004-11-11 00:16 ivan + + * install/fedora/fc2/INSTALL: last wo + +2004-11-11 00:13 ivan + + * install/fedora/fc2/INSTALL: cats help alot + +2004-11-10 23:44 ivan + + * install/fedora/fc2/: INSTALL, sources.list: adding fc2 install + 2004-11-09 03:42 ivan * httemplate/search/report_tax.cgi: add handling for texas tax @@ -19492,11 +23337,23 @@ * ANNOUNCE.1.5.0, httemplate/docs/install.html: update install documentation for 1.5 HTML::Mason or Apache::ASP install +2004-11-04 01:45 ivan + + * install/debian/3.0/INSTALL: and the last two runtime ones + +2004-11-04 01:26 ivan + + * install/debian/3.0/INSTALL: few additional dependancies + 2004-10-30 17:01 ivan * httemplate/search/cust_main-quickpay.html: quick pay shouldnt default to exact search +2004-10-26 05:43 ivan + + * install/redhat/es3/: INSTALL, httpd-init: adding rh es3 files + 2004-10-26 05:36 ivan * Makefile: 1.5.0pre6! @@ -19767,6 +23624,24 @@ * ANNOUNCE.1.5.0: [no log message] +2004-09-30 18:38 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: -w flag spewing too + much to STDOUT + +2004-09-27 16:17 ivan + + * install/redhat/8/INSTALL: please don't use rh8 + +2004-09-27 13:42 ivan + + * install/redhat/8/INSTALL: apachetoolbox instead i guess + +2004-09-27 13:37 ivan + + * install/redhat/8/: INSTALL, README.insecure, sources.list: adding + rh8 install foo and warning + 2004-09-22 04:28 ivan * httemplate/search/: cust_bill_event.html, @@ -19869,7 +23744,9 @@ 2004-09-05 15:42 ivan - * fs_selfservice/FS-SelfService/cgi/signup.html: fixed duplicate + * fs_selfservice/FS-SelfService/cgi/signup.html, + fs_signup/FS-SignupClient/cgi/signup-agentselect.html, + fs_signup/FS-SignupClient/cgi/signup.html: fixed duplicate checking will catch it, but add client-side protection against double-submission also. @@ -20117,6 +23994,12 @@ * htetc/: global.asa, handler.pl: 0.32 (and then some) released +2004-07-06 01:31 ivan + + * install/5.005/Net-Whois-Raw/: COPYRIGHT, Changes, MANIFEST, + META.yml, Makefile.PL, README, pwhois, lib/Net/Whois/Raw.pm, + lib/Net/Whois/Raw/Data.pm, t/01.t: 0.32 (and then some) released + 2004-07-01 06:49 ivan * FS/FS/: ClientAPI/MyAccount.pm, cust_main.pm: credit out @@ -20243,6 +24126,11 @@ * fs_selfservice/FS-SelfService/cgi/agent.cgi: fix dup password checking on add'l package order +2004-06-21 07:20 ivan + + * fs_signup/FS-SignupClient/SignupClient.pm: export popselector and + expselect + 2004-06-21 06:36 ivan * FS/MANIFEST: removing old report from MANIFEST @@ -20348,7 +24236,9 @@ fs_selfservice/FS-SelfService/cgi/signup.html, fs_selfservice/FS-SelfService/cgi/view_customer.html, httemplate/browse/agent.cgi, httemplate/search/cust_main.cgi, - fs_selfservice/FS-SelfService/SelfService.pm: agent interface + fs_selfservice/FS-SelfService/SelfService.pm, + fs_signup/FS-SignupClient/SignupClient.pm, + fs_signup/FS-SignupClient/cgi/signup.cgi: agent interface 2004-06-10 04:28 ivan @@ -20572,6 +24462,10 @@ * bin/: sequences.reset, freeside.import: adding +2004-05-12 05:38 ivan + + * install/redhat/9/: INSTALL, sources.list: that wasn't pleasant + 2004-05-12 03:03 ivan * Makefile: for native apache installs @@ -20712,6 +24606,11 @@ * httemplate/search/cust_bill.html: handle missing customer records without erroring out +2004-05-01 03:43 ivan + + * install/redhat/9/INSTALL: update for some new atrpms package + versions + 2004-04-30 20:54 ivan * htetc/global.asa: very weird 5.005 problem @@ -20729,6 +24628,71 @@ * httemplate/index.html: 15 day open invoice reports for qis +2004-04-29 06:08 ivan + + * fs_signup/FS-SignupClient/cgi/: map.gif, stateselect.html: + imagemap for state selection + +2004-04-29 02:24 ivan + + * install/5.005/Net-Whois-Raw/lib/Net/Whois/Raw/Data.pm: 5.005 fix + +2004-04-29 02:21 ivan + + * install/5.005/: DBIx-DBSchema-0.23-5.005kludge/Changes, + DBIx-DBSchema-0.23-5.005kludge/DBSchema.pm, + DBIx-DBSchema-0.23-5.005kludge/MANIFEST, + DBIx-DBSchema-0.23-5.005kludge/MANIFEST.SKIP, + DBIx-DBSchema-0.23-5.005kludge/Makefile.PL, + DBIx-DBSchema-0.23-5.005kludge/README, + DBIx-DBSchema-0.23-5.005kludge/TODO, + DBD-Pg-1.22-fixvercmp/Changes, DBD-Pg-1.22-fixvercmp/MANIFEST, + DBD-Pg-1.22-fixvercmp/Makefile.PL, DBD-Pg-1.22-fixvercmp/Pg.h, + DBD-Pg-1.22-fixvercmp/Pg.pm, DBD-Pg-1.22-fixvercmp/Pg.xs, + DBD-Pg-1.22-fixvercmp/README, DBD-Pg-1.22-fixvercmp/README.win32, + DBD-Pg-1.22-fixvercmp/dbd-pg.pod, DBD-Pg-1.22-fixvercmp/dbdimp.c, + DBD-Pg-1.22-fixvercmp/dbdimp.h, + DBD-Pg-1.22-fixvercmp/eg/ApacheDBI.pl, + DBD-Pg-1.22-fixvercmp/eg/lotest.pl, + DBD-Pg-1.22-fixvercmp/eg/notify_test.patch, + DBD-Pg-1.22-fixvercmp/t/00basic.t, + DBD-Pg-1.22-fixvercmp/t/01connect.t, + DBD-Pg-1.22-fixvercmp/t/01constants.t, + DBD-Pg-1.22-fixvercmp/t/01setup.t, + DBD-Pg-1.22-fixvercmp/t/02prepare.t, + DBD-Pg-1.22-fixvercmp/t/03bind.t, + DBD-Pg-1.22-fixvercmp/t/04execute.t, + DBD-Pg-1.22-fixvercmp/t/05fetch.t, + DBD-Pg-1.22-fixvercmp/t/06disconnect.t, + DBD-Pg-1.22-fixvercmp/t/07reuse.t, + DBD-Pg-1.22-fixvercmp/t/08txn.t, + DBD-Pg-1.22-fixvercmp/t/09autocommit.t, + DBD-Pg-1.22-fixvercmp/t/11quoting.t, + DBD-Pg-1.22-fixvercmp/t/12placeholders.t, + DBD-Pg-1.22-fixvercmp/t/13pgtype.t, + DBD-Pg-1.22-fixvercmp/t/15funct.t, + DBD-Pg-1.22-fixvercmp/t/99cleanup.t, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Request.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Util.pm, + DBIx-DBSchema-0.23-5.005kludge/t/load-mysql.t, + DBIx-DBSchema-0.23-5.005kludge/t/load-pg.t, + DBIx-DBSchema-0.23-5.005kludge/t/load.t, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/Handler/Prompt.pm, + DBD-Pg-1.22-fixvercmp/t/lib/App/Info/RDBMS/PostgreSQL.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/Column.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/Table.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Index.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/ColGroup/Unique.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Pg.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/Sybase.pm, + DBIx-DBSchema-0.23-5.005kludge/DBSchema/DBD/mysql.pm: adding + DBD::Pg and DBIx::DBSchema for 5.005. argh freebsd and solaris! + 2004-04-23 06:15 ivan * FS/MANIFEST, FS/bin/freeside-cc-receipts-report, @@ -20800,6 +24764,11 @@ httemplate/view/cust_main.cgi: add methods for masking credit cards, add payment info modification to self-service +2004-04-13 20:20 ivan + + * install/fedora/fc1/: INSTALL, sources.list: adding preliminary + install script for fedora core 1 + 2004-04-13 18:00 ivan * rt/FREESIDE_MODIFIED: keeping track of what's been changed to @@ -20896,6 +24865,12 @@ * httemplate/view/svc_domain.cgi: javascript confirm when slaving a domain +2004-04-07 02:08 ivan + + * install/5.005/Net-Whois-Raw/: COPYRIGHT, Changes, MANIFEST, + META.yml, Makefile.PL, README, pwhois, t/01.t, + lib/Net/Whois/Raw.pm, lib/Net/Whois/Raw/Data.pm: Initial revision + 2004-04-07 01:34 ivan * FS/FS/part_export.pm: argh, the glob itself is tainted under @@ -21278,6 +25253,11 @@ * Makefile: dont want to error out here +2004-03-15 11:22 ivan + + * fs_signup/FS-SignupClient/: MANIFEST, Makefile.PL, fs_signupd: + signup is now just a wrapper around self-service + 2004-03-12 17:27 ivan * Makefile: really add the necessary backslashes this time, fix @@ -21366,6 +25346,14 @@ * FS/MANIFEST: incorrect listing in MANIFEST +2004-03-10 19:53 ivan + + * install/redhat/7.3/INSTALL: 1.5 stuff + +2004-03-10 18:21 ivan + + * install/suse/9.0/INSTALL: suse install script + 2004-03-10 18:03 ivan * rt/lib/: RT/I18N/it.po, RT/Interface/REST.pm, @@ -21401,6 +25389,15 @@ weren't being properly masked on errors. The router/block select box wasn't being generated on errors. +2004-03-10 13:47 ivan + + * install/suse/: INSTALL, 9.0/INSTALL: move to versioned dir + +2004-03-10 13:44 ivan + + * install/: redhat/9/INSTALL, suse/INSTALL: adding preliminary suse + install script + 2004-03-10 11:06 khoff * httemplate/browse/router.cgi: Added hide/show customer router @@ -21479,6 +25476,10 @@ * httemplate/edit/process/cust_main_county.cgi: new setuptax and recurtax fields +2004-02-28 14:36 ivan + + * install/redhat/7.3/INSTALL: update + 2004-02-28 14:26 ivan * FS/FS/Record.pm: depend on DBIx::DBSchema 0.23 and thus DBD::Pg @@ -21584,6 +25585,10 @@ forward_shellcommands.pm, shellcommands.pm, www_shellcommands.pm: depend on Net::SSH 0.08 for non-blocking STDERR read +2004-02-12 14:40 ivan + + * install/redhat/9/INSTALL: doc + 2004-02-12 02:44 ivan * bin/bind.import: fix usage msg @@ -21614,10 +25619,34 @@ * bin/shadow.reimport: adding shadow.reimport +2004-02-01 16:23 ivan + + * install/redhat/9/INSTALL: add 1.5 dependancies + +2004-02-01 13:07 ivan + + * install/redhat/9/INSTALL: add addl dependancies, should work now? + +2004-02-01 13:05 ivan + + * install/redhat/9/INSTALL: rar rar + +2004-02-01 13:00 ivan + + * install/redhat/9/INSTALL: rar + +2004-02-01 01:43 ivan + + * install/debian/3.0/INSTALL: add libcache-cache-perl + 2004-02-01 01:29 ivan * Makefile: use install to make all components of FREESIDE_CONF dir +2004-02-01 01:23 ivan + + * install/debian/3.0/INSTALL: s/cleanwhisker/pouncequick/ + 2004-01-30 22:33 ivan * FS/FS/part_pkg.pm, FS/FS/pkg_svc.pm, @@ -21797,6 +25826,10 @@ * httemplate/view/cust_bill-pdf.cgi: adding +2004-01-10 03:32 ivan + + * install/redhat/9/INSTALL: update paths + 2004-01-10 03:17 ivan * Makefile: workaround stubborn shells globbing [a-z] to include @@ -21846,6 +25879,11 @@ * httemplate/index.html: fix other packages by next bill date link +2004-01-03 20:44 ivan + + * fs_signup/FS-SignupClient/Makefile.PL: no more + HTTP::Headers::UserAgent! + 2004-01-03 19:54 ivan * httemplate/docs/signup.html: remove obsolete netscape CCK @@ -21854,6 +25892,14 @@ depend on HTTP::BrowserDetect directly instead of via deprecated HTTP::Headers::UserAgent (closes: Bug#578) +2004-01-03 19:52 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: remove obsolete + netscape CCK support + + depend on HTTP::BrowserDetect directly instead of via deprecated + HTTP::Headers::UserAgent (closes: Bug#578) + 2004-01-03 00:42 ivan * httemplate/browse/agent.cgi: fix heading colspan when there is no @@ -21981,8 +26027,10 @@ 2003-12-10 15:53 ivan - * FS/FS/ClientAPI/Signup.pm: signup page w/advertising source - dropdown + * FS/FS/ClientAPI/Signup.pm, + fs_signup/FS-SignupClient/cgi/signup.cgi, + fs_signup/FS-SignupClient/cgi/signup.html: signup page + w/advertising source dropdown 2003-12-10 14:51 ivan @@ -22134,6 +26182,10 @@ * httemplate/search/report_receivables.cgi: sort these case-insensitive +2003-11-13 03:23 ivan + + * install/debian/3.0/INSTALL: fix path in questionable section + 2003-11-12 04:29 ivan * FS/FS/: svc_Common.pm, svc_acct.pm: allow provisioning of @@ -22326,8 +26378,15 @@ 2003-10-24 19:05 ivan - * FS/FS/: acct_snarf.pm, svc_Common.pm, svc_acct.pm, - ClientAPI/Signup.pm: signups with snarf info! + * FS/FS/acct_snarf.pm, FS/FS/svc_Common.pm, FS/FS/svc_acct.pm, + FS/FS/ClientAPI/Signup.pm, + fs_signup/FS-SignupClient/cgi/signup.cgi: signups with snarf + info! + +2003-10-24 19:05 ivan + + * fs_signup/FS-SignupClient/cgi/signup-snarf.html: adding signup + with snarf input 2003-10-24 18:06 ivan @@ -22341,10 +26400,17 @@ 2003-10-24 12:28 ivan - * FS/FS/ClientAPI/Signup.pm, httemplate/edit/cust_main.cgi, + * FS/FS/ClientAPI/Signup.pm, + fs_signup/FS-SignupClient/SignupClient.pm, + fs_signup/FS-SignupClient/cgi/signup.cgi, + fs_signup/FS-SignupClient/cgi/signup.html, + httemplate/edit/cust_main.cgi, httemplate/edit/process/cust_main.cgi, httemplate/docs/cvv2.html, httemplate/docs/upgrade10.html, FS/FS/cust_main.pm, - FS/bin/freeside-setup, httemplate/docs/schema.html: cvv! + FS/bin/freeside-setup, fs_signup/FS-SignupClient/cgi/cvv2.html, + fs_signup/FS-SignupClient/cgi/cvv2.png, + fs_signup/FS-SignupClient/cgi/cvv2_amex.png, + httemplate/docs/schema.html: cvv! 2003-10-23 22:51 ivan @@ -22378,6 +26444,18 @@ * httemplate/edit/process/router.cgi: dbh is a global. +2003-10-20 18:28 ivan + + * install/redhat/9/INSTALL: more rh9 install foo + +2003-10-20 17:07 ivan + + * install/redhat/9/INSTALL: update rh9 install foo + +2003-10-20 11:59 ivan + + * install/redhat/: 7.3/INSTALL, 9/INSTALL: add passive flag to wget + 2003-10-19 22:01 ivan * FS/FS/cust_main.pm, httemplate/edit/part_pkg.cgi, @@ -22389,6 +26467,16 @@ httemplate/edit/part_pkg.cgi, httemplate/docs/upgrade10.html, FS/bin/freeside-setup: daily/weekly billing +2003-10-19 19:35 ivan + + * install/redhat/9/: INSTALL, sources.list: update for rh9 + +2003-10-19 19:28 ivan + + * install/: openbsd/INSTALL, openbsd/cpan, openbsd/ports, + redhat/9/INSTALL, redhat/9/sources.list: adding openbsd and red + hat installs + 2003-10-19 11:08 ivan * httemplate/docs/install.html: fix CPAN link @@ -22437,6 +26525,11 @@ processors (AuthorozeNet, others?) use this to waive the CVV2 requirement. +2003-10-14 09:59 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: fix the default success + template + 2003-10-09 10:40 ivan * FS/FS/cust_pay_batch.pm: parse last line from TD Canada Trust @@ -22530,7 +26623,8 @@ 2003-10-02 05:42 ivan - * fs_selfservice/FS-SelfService/Makefile.PL: update Makefile.PL + * fs_selfservice/FS-SelfService/Makefile.PL, + fs_signup/FS-SignupClient/Makefile.PL: update Makefile.PL dependancies (PREREQ_PM) for self-service module and signup wrapper @@ -22589,12 +26683,19 @@ 2003-09-28 23:51 ivan - * FS/FS/ClientAPI/Signup.pm: signup with agent selection + * FS/FS/ClientAPI/Signup.pm, + fs_signup/FS-SignupClient/cgi/signup-agentselect.html, + fs_signup/FS-SignupClient/cgi/signup.cgi: signup with agent + selection 2003-09-28 23:35 ivan * httemplate/index.html: remove Gratuitous Capitalization +2003-09-28 23:22 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: eliminate warning + 2003-09-28 22:51 ivan * FS/FS/agent.pm, httemplate/browse/agent.cgi, @@ -22707,6 +26808,10 @@ * FS/FS/part_export/shellcommands.pm: don't allow uid changes when usermod_pwonly set +2003-09-23 19:37 ivan + + * install/freebsd/ports: need Cache::Cache in 1.4.2+ + 2003-09-23 18:30 ivan * httemplate/browse/agent.cgi: fix boolean precedence error leading @@ -22734,6 +26839,11 @@ * FS/FS/cust_main.pm: quiet option to cancel method +2003-09-19 05:19 ivan + + * fs_signup/FS-SignupClient/SignupClient.pm: fix + backwards-compatibility for signup server + 2003-09-19 05:13 ivan * FS/FS/ClientAPI/Signup.pm: remove klunky $error ||= usage @@ -22773,9 +26883,11 @@ 2003-09-19 03:07 ivan * Makefile, FS/FS/Conf.pm, FS/FS/cust_main.pm, FS/FS/cust_pkg.pm, - FS/FS/ClientAPI/Signup.pm, httemplate/docs/index.html: move - signup server functions to self-service server. fix provisioning - & immediate suspension of declined signups. + FS/FS/ClientAPI/Signup.pm, + fs_signup/FS-SignupClient/SignupClient.pm, + httemplate/docs/index.html: move signup server functions to + self-service server. fix provisioning & immediate suspension of + declined signups. 2003-09-19 02:59 ivan @@ -22943,6 +27055,18 @@ * Makefile: makefile trivia for openbsd +2003-08-21 00:42 ivan + + * install/debian/3.0/INSTALL: woody backports + +2003-08-20 23:46 ivan + + * install/debian/3.0/INSTALL: iffy + +2003-08-20 23:42 ivan + + * install/debian/3.0/INSTALL: woody + 2003-08-07 22:54 ivan * httemplate/view/svc_acct.cgi: - fix possible glitch with Mason on @@ -23129,18 +27253,136 @@ lib/RT/Condition/AnyTransaction.pm, lib/RT/Condition/Generic.pm, lib/RT/Condition/NewDependency.pm, lib/RT/Condition/StatusChange.pm, lib/RT/Interface/CLI.pm, - lib/RT/Interface/Email.pm, lib/RT/Interface/Web.pm: reverting to - vendor branch rt 3.0.4, hopefully + lib/RT/Interface/Email.pm, lib/RT/Interface/Web.pm, + tools/cpan2rpm, tools/initdb, tools/insertdata, tools/testdeps, + webrt/autohandler, webrt/index.html, webrt/Admin/index.html, + webrt/Admin/Elements/CreateQueueCalled, + webrt/Admin/Elements/CreateUserCalled, + webrt/Admin/Elements/EditUserComments, + webrt/Admin/Elements/GrantQueueRightsTo, + webrt/Admin/Elements/GroupTabs, webrt/Admin/Elements/Header, + webrt/Admin/Elements/ListGlobalKeywordSelects, + webrt/Admin/Elements/ListGlobalScrips, + webrt/Admin/Elements/ModifyKeyword, + webrt/Admin/Elements/ModifyKeywordSelect, + webrt/Admin/Elements/ModifyQueue, + webrt/Admin/Elements/ModifyTemplate, + webrt/Admin/Elements/ModifyUser, + webrt/Admin/Elements/QueueRightsForUser, + webrt/Admin/Elements/QueueTabs, + webrt/Admin/Elements/SelectKeywordSelect, + webrt/Admin/Elements/SelectModifyGroup, + webrt/Admin/Elements/SelectModifyKeyword, + webrt/Admin/Elements/SelectModifyKeywordSelect, + webrt/Admin/Elements/SelectModifyQueue, + webrt/Admin/Elements/SelectModifyUser, + webrt/Admin/Elements/SelectQueueRights, + webrt/Admin/Elements/SelectRights, + webrt/Admin/Elements/SelectScrip, + webrt/Admin/Elements/SelectScripAction, + webrt/Admin/Elements/SelectScripCondition, + webrt/Admin/Elements/SelectSingleOrMultiple, + webrt/Admin/Elements/SelectTemplate, + webrt/Admin/Elements/SelectUsers, + webrt/Admin/Elements/SystemTabs, webrt/Admin/Elements/Tabs, + webrt/Admin/Elements/UserTabs, + webrt/Admin/Global/GroupRights.html, + webrt/Admin/Global/Keywords.html, webrt/Admin/Global/Scrips.html, + webrt/Admin/Global/Template.html, + webrt/Admin/Global/Templates.html, + webrt/Admin/Global/UserRights.html, + webrt/Admin/Global/index.html, webrt/Admin/Groups/Members.html, + webrt/Admin/Groups/Modify.html, webrt/Admin/Groups/Rights.html, + webrt/Admin/Groups/index.html, + webrt/Admin/KeywordSelects/Modify.html, + webrt/Admin/KeywordSelects/index.html, + webrt/Admin/Keywords/Modify.html, + webrt/Admin/Keywords/index.html, webrt/Admin/Queues/Create.html, + webrt/Admin/Queues/GroupRights.html, + webrt/Admin/Queues/Keywords.html, webrt/Admin/Queues/Modify.html, + webrt/Admin/Queues/People.html, webrt/Admin/Queues/Scrips.html, + webrt/Admin/Queues/Template.html, + webrt/Admin/Queues/Templates.html, + webrt/Admin/Queues/UserRights.html, + webrt/Admin/Queues/index.html, webrt/Admin/Users/Modify.html, + webrt/Admin/Users/Prefs.html, webrt/Admin/Users/Rights.html, + webrt/Admin/Users/index.html, webrt/Elements/Checkbox, + webrt/Elements/CreateTicket, webrt/Elements/CustomHomepageHeader, + webrt/Elements/Error, webrt/Elements/Footer, + webrt/Elements/GotoTicket, webrt/Elements/Header, + webrt/Elements/ListActions, webrt/Elements/Login, + webrt/Elements/MessageBox, webrt/Elements/MyRequests, + webrt/Elements/MyTickets, webrt/Elements/Quicksearch, + webrt/Elements/Refresh, webrt/Elements/Section, + webrt/Elements/SelectBoolean, webrt/Elements/SelectDate, + webrt/Elements/SelectDateRelation, webrt/Elements/SelectDateType, + webrt/Elements/SelectEqualityOperator, + webrt/Elements/SelectKeyword, + webrt/Elements/SelectKeywordOptions, + webrt/Elements/SelectLinkType, webrt/Elements/SelectMatch, + webrt/Elements/SelectNewTicketQueue, webrt/Elements/SelectOwner, + webrt/Elements/SelectQueue, webrt/Elements/SelectResultsPerPage, + webrt/Elements/SelectSortOrder, webrt/Elements/SelectStatus, + webrt/Elements/SelectTicketSortBy, webrt/Elements/SelectUsers, + webrt/Elements/SelectWatcherType, webrt/Elements/ShadedBox, + webrt/Elements/Submit, webrt/Elements/Tabs, + webrt/Elements/TitleBoxEnd, webrt/Elements/TitleBoxStart, + webrt/Elements/ViewUser, webrt/Elements/dayMenu, + webrt/Elements/monthMenu, webrt/Elements/yearMenu, + webrt/NoAuth/Logout.html, webrt/NoAuth/Reminder.html, + webrt/NoAuth/webrt.css, webrt/NoAuth/images/rt.jpg, + webrt/NoAuth/images/spacer.gif, webrt/Search/Bulk.html, + webrt/Search/Listing.html, webrt/Search/PickRestriction, + webrt/Search/RestrictSearch.html, webrt/Search/TicketCell, + webrt/SelfService/Closed.html, webrt/SelfService/Create.html, + webrt/SelfService/Display.html, webrt/SelfService/Error.html, + webrt/SelfService/Prefs.html, webrt/SelfService/Update.html, + webrt/SelfService/index.html, + webrt/SelfService/Attachment/dhandler, + webrt/SelfService/Elements/GotoTicket, + webrt/SelfService/Elements/Header, + webrt/SelfService/Elements/MyRequests, + webrt/SelfService/Elements/Tabs, webrt/Ticket/Create.html, + webrt/Ticket/Display.html, webrt/Ticket/History.html, + webrt/Ticket/Modify.html, webrt/Ticket/ModifyAll.html, + webrt/Ticket/ModifyDates.html, webrt/Ticket/ModifyLinks.html, + webrt/Ticket/ModifyPeople.html, webrt/Ticket/Update.html, + webrt/Ticket/Attachment/dhandler, + webrt/Ticket/Elements/AddWatchers, + webrt/Ticket/Elements/EditBasics, + webrt/Ticket/Elements/EditDates, + webrt/Ticket/Elements/EditKeywordSelects, + webrt/Ticket/Elements/EditLinks, + webrt/Ticket/Elements/EditPeople, + webrt/Ticket/Elements/EditWatchers, + webrt/Ticket/Elements/ShowBasics, + webrt/Ticket/Elements/ShowDates, + webrt/Ticket/Elements/ShowDependencies, + webrt/Ticket/Elements/ShowHistory, + webrt/Ticket/Elements/ShowKeywordSelects, + webrt/Ticket/Elements/ShowLinks, + webrt/Ticket/Elements/ShowMemberOf, + webrt/Ticket/Elements/ShowMembers, + webrt/Ticket/Elements/ShowPeople, + webrt/Ticket/Elements/ShowReferences, + webrt/Ticket/Elements/ShowRequestor, + webrt/Ticket/Elements/ShowSummary, + webrt/Ticket/Elements/ShowTransaction, + webrt/Ticket/Elements/Tabs, webrt/Ticket/Elements/ToolBar, + webrt/User/Prefs.html: reverting to vendor branch rt 3.0.4, + hopefully 2003-07-15 06:16 ivan * rt/: Makefile.in, aclocal.m4, config, config.layout, Changelog, config.log, config.pld, config.status, configure, configure.ac, - install-sh, bin/mason_handler.fcgi.in, bin/mason_handler.scgi.in, - bin/mason_handler.svc, bin/mason_handler.svc.in, - bin/rt-commit-handler, bin/rt-commit-handler.in, - bin/rt-crontool.in, bin/rt-mailgate.in, bin/webmux.pl.in, - bin/rt-crontool, docs/design_docs/approval_notices, + install-sh, HOWTO/README, HOWTO/change.txt, HOWTO/release.txt, + HOWTO/version-control.txt, bin/mason_handler.fcgi.in, + bin/mason_handler.scgi.in, bin/mason_handler.svc, + bin/mason_handler.svc.in, bin/rt-commit-handler, + bin/rt-commit-handler.in, bin/rt-crontool.in, bin/rt-mailgate.in, + bin/webmux.pl.in, bin/rt-crontool, + docs/design_docs/approval_notices, docs/design_docs/approval_template, docs/design_docs/cf_search, docs/design_docs/delegation, docs/design_docs/groups_notes, docs/design_docs/recursive_group_membership_algorithm, @@ -23355,6 +27597,326 @@ autom4te.cache/traces.0, sbin/rt-test-dependencies: Initial revision +2003-07-15 04:44 ivan + + * sql-ledger/: VERSION, am.pl, favicon.ico, login.pl, menu.ini, + setup.pl, sql-ledger.conf.default, sql-ledger.png, SL/AM.pm, + SL/AP.pm, SL/AR.pm, SL/CT.pm, SL/Form.pm, SL/GL.pm, SL/IC.pm, + SL/IR.pm, SL/IS.pm, SL/User.pm, SL/CA.pm, SL/CP.pm, + SL/Inifile.pm, SL/Mailer.pm, SL/Menu.pm, SL/Num2text.pm, + SL/OE.pm, SL/PE.pm, SL/RC.pm, SL/RP.pm, bin/lynx/menu.pl, + bin/mozilla/admin.pl, bin/mozilla/am.pl, bin/mozilla/ap.pl, + bin/mozilla/ar.pl, bin/mozilla/ca.pl, bin/mozilla/ct.pl, + bin/mozilla/gl.pl, bin/mozilla/ic.pl, bin/mozilla/io.pl, + bin/mozilla/ir.pl, bin/mozilla/login.pl, bin/mozilla/menu.pl, + bin/mozilla/arap.pl, bin/mozilla/cp.pl, bin/mozilla/is.pl, + bin/mozilla/oe.pl, bin/mozilla/pe.pl, bin/mozilla/rc.pl, + bin/mozilla/rp.pl, css/sql-ledger.css, doc/COPYING, doc/README, + doc/UPGRADE-1.6-1.8, doc/UPGRADE-1.8-1.8.3, + doc/UPGRADE-1.8.3-1.8.4, doc/UPGRADE-1.8.4-1.8.5, + doc/UPGRADE-1.8.5-1.8.7, doc/UPGRADE-1.8.7-2.0.0, + doc/UPGRADE-2.0-2.0.8, doc/copyright, doc/faq.html, + locale/de/admin, locale/de/COPYING, locale/de/LANGUAGE, + locale/de/Num2text, locale/de/all, locale/de/am, locale/de/ap, + locale/de/ar, locale/de/arap, locale/de/ca, locale/de/cp, + locale/de/ct, locale/de/gl, locale/de/ic, locale/de/io, + locale/de/ir, locale/de/is, locale/de/locales.pl, + locale/de/login, locale/de/menu, locale/de/oe, locale/de/pe, + locale/de/rc, locale/de/rp, locale/fr/admin, locale/fr/all, + locale/fr/am, locale/fr/ap, locale/fr/ar, locale/fr/ca, + locale/fr/ct, locale/fr/gl, locale/fr/ic, locale/fr/io, + locale/es/COPYING, locale/es/LANGUAGE, locale/es/Num2text, + locale/es/admin, locale/es/all, locale/es/am, locale/es/ap, + locale/es/ar, locale/es/arap, locale/es/ca, locale/es/cp, + locale/es/ct, locale/es/gl, locale/es/ic, locale/es/io, + locale/es/ir, locale/es/is, locale/es/login, locale/es/menu, + locale/es/oe, locale/es/pe, locale/es/rc, locale/es/rp, + locale/fr/COPYING, locale/fr/LANGUAGE, locale/fr/arap, + locale/fr/cp, locale/fr/ir, locale/fr/is, locale/fr/login, + locale/fr/menu, locale/fr/oe, locale/fr/pe, locale/fr/rc, + locale/fr/rp, locale/tw/admin, locale/tw/login, + locale/dk/LANGUAGE, locale/dk/admin, locale/dk/all, locale/dk/am, + locale/dk/ap, locale/dk/ar, locale/dk/arap, locale/dk/ca, + locale/dk/ct, locale/dk/gl, locale/dk/ic, locale/dk/io, + locale/dk/ir, locale/dk/is, locale/dk/login, locale/dk/menu, + locale/dk/oe, locale/dk/rp, locale/tw/COPYING, + locale/tw/LANGUAGE, locale/tw/all, locale/tw/am, locale/tw/ap, + locale/tw/ar, locale/tw/arap, locale/tw/ca, locale/tw/cp, + locale/tw/ct, locale/tw/gl, locale/tw/ic, locale/tw/io, + locale/tw/ir, locale/tw/is, locale/tw/menu, locale/tw/oe, + locale/tw/pe, locale/tw/rc, locale/tw/rp, locale/br/COPYING, + locale/br/LANGUAGE, locale/br/admin, locale/br/all, locale/br/am, + locale/br/ap, locale/br/ar, locale/br/arap, locale/br/ca, + locale/br/cp, locale/br/ct, locale/br/gl, locale/br/ic, + locale/br/io, locale/br/ir, locale/br/is, locale/br/login, + locale/br/menu, locale/br/oe, locale/br/pe, locale/br/rc, + locale/br/rp, locale/dk/COPYING, locale/dk/cp, locale/dk/pe, + locale/dk/rc, locale/it/admin, locale/it/ap, locale/it/ar, + locale/it/ca, locale/it/ct, locale/it/gl, locale/it/ic, + locale/it/ir, locale/it/menu, locale/ct/COPYING, + locale/ct/LANGUAGE, locale/ct/admin, locale/ct/all, locale/ct/am, + locale/ct/ap, locale/ct/ar, locale/ct/ca, locale/ct/ct, + locale/ct/gl, locale/ct/ic, locale/ct/io, locale/ct/ir, + locale/ct/is, locale/ct/login, locale/ct/menu, locale/ct/oe, + locale/ct/rp, locale/it/COPYING, locale/it/LANGUAGE, + locale/it/Num2text, locale/it/all, locale/it/am, locale/it/arap, + locale/it/cp, locale/it/io, locale/it/is, locale/it/login, + locale/it/oe, locale/it/pe, locale/it/qe, locale/it/rc, + locale/it/rp, locale/ct/arap, locale/ct/cp, locale/ct/pe, + locale/ct/rc, locale/ee/COPYING, locale/ee/LANGUAGE, + locale/ee/admin, locale/ee/all, locale/ee/am, locale/ee/ap, + locale/ee/ar, locale/ee/arap, locale/ee/ca, locale/ee/cp, + locale/ee/ct, locale/ee/gl, locale/ee/ic, locale/ee/io, + locale/ee/ir, locale/ee/is, locale/ee/login, locale/ee/menu, + locale/ee/oe, locale/ee/pe, locale/ee/rc, locale/ee/rp, + locale/nl/admin, locale/nl/all, locale/nl/am, locale/nl/ap, + locale/nl/ar, locale/nl/ca, locale/nl/ct, locale/nl/gl, + locale/nl/COPYING, locale/nl/LANGUAGE, locale/nl/Num2text, + locale/nl/arap, locale/nl/cp, locale/nl/ic, locale/nl/io, + locale/nl/ir, locale/nl/is, locale/nl/login, locale/nl/menu, + locale/nl/oe, locale/nl/pe, locale/nl/rc, locale/nl/rp, + locale/no/COPYING, locale/no/LANGUAGE, locale/no/admin, + locale/no/all, locale/no/am, locale/no/ap, locale/no/ar, + locale/no/arap, locale/no/ca, locale/no/cp, locale/no/ct, + locale/no/gl, locale/no/ic, locale/no/io, locale/no/ir, + locale/no/is, locale/no/login, locale/no/menu, locale/no/oe, + locale/no/pe, locale/no/rc, locale/no/rp, locale/tr/COPYING, + locale/tr/LANGUAGE, locale/tr/admin, locale/tr/all, locale/tr/am, + locale/tr/ap, locale/tr/ar, locale/tr/arap, locale/tr/ca, + locale/tr/cp, locale/tr/ct, locale/tr/gl, locale/tr/ic, + locale/tr/io, locale/tr/ir, locale/tr/is, locale/tr/login, + locale/tr/menu, locale/tr/oe, locale/tr/pe, locale/tr/rc, + locale/tr/rp, locale/ve/COPYING, locale/ve/admin, locale/ve/all, + locale/ve/am, locale/ve/ap, locale/ve/ar, locale/ve/ca, + locale/ve/ct, locale/ve/gl, locale/ve/ic, locale/ve/ir, + locale/ve/is, locale/ve/login, locale/ve/rp, locale/cz/admin, + locale/cz/all, locale/cz/am, locale/pa/COPYING, + locale/pa/LANGUAGE, locale/pa/admin, locale/pa/all, locale/pa/am, + locale/pa/ap, locale/pa/ar, locale/pa/arap, locale/pa/ca, + locale/pa/cp, locale/pa/ct, locale/pa/gl, locale/pa/ic, + locale/pa/io, locale/pa/ir, locale/pa/is, locale/pa/login, + locale/pa/menu, locale/pa/oe, locale/pa/pe, locale/pa/rc, + locale/pa/rp, locale/ve/LANGUAGE, locale/ve/arap, locale/ve/cp, + locale/ve/io, locale/ve/menu, locale/ve/oe, locale/ve/pe, + locale/ve/rc, locale/cz/COPYING, locale/cz/LANGUAGE, + locale/cz/ap, locale/cz/ar, locale/cz/arap, locale/cz/ca, + locale/cz/cp, locale/cz/ct, locale/cz/gl, locale/cz/ic, + locale/cz/io, locale/cz/ir, locale/cz/is, locale/cz/login, + locale/cz/menu, locale/cz/oe, locale/cz/pe, locale/cz/rc, + locale/cz/rp, locale/pt/COPYING, locale/pt/LANGUAGE, + locale/pt/admin, locale/pt/all, locale/pt/am, locale/pt/ap, + locale/pt/ar, locale/pt/arap, locale/pt/ca, locale/pt/cp, + locale/pt/ct, locale/pt/gl, locale/pt/ic, locale/pt/io, + locale/pt/ir, locale/pt/is, locale/pt/login, locale/pt/menu, + locale/pt/oe, locale/pt/pe, locale/pt/rc, locale/pt/rp, + locale/cn/COPYING, locale/cn/LANGUAGE, locale/cn/admin, + locale/cn/all, locale/cn/am, locale/cn/ap, locale/cn/ar, + locale/cn/arap, locale/cn/ca, locale/cn/cp, locale/cn/ct, + locale/cn/gl, locale/cn/ic, locale/cn/io, locale/cn/ir, + locale/cn/is, locale/cn/login, locale/cn/menu, locale/cn/oe, + locale/cn/pe, locale/cn/rc, locale/cn/rp, locale/pl/admin, + locale/pl/all, locale/pl/am, locale/pl/ap, locale/pl/ar, + locale/pl/ca, locale/pl/ct, locale/pl/gl, locale/pl/ic, + locale/pl/ir, locale/fi/COPYING, locale/fi/LANGUAGE, + locale/fi/admin, locale/fi/all, locale/mx/COPYING, + locale/mx/LANGUAGE, locale/mx/admin, locale/mx/all, locale/mx/am, + locale/mx/ap, locale/mx/ar, locale/mx/arap, locale/mx/ca, + locale/mx/cp, locale/mx/ct, locale/mx/gl, locale/mx/ic, + locale/mx/io, locale/mx/ir, locale/mx/is, locale/mx/login, + locale/mx/menu, locale/mx/oe, locale/mx/pe, locale/mx/rc, + locale/mx/rp, locale/pl/COPYING, locale/pl/LANGUAGE, + locale/pl/arap, locale/pl/cp, locale/pl/io, locale/pl/is, + locale/pl/login, locale/pl/menu, locale/pl/oe, locale/pl/pe, + locale/pl/rc, locale/pl/rp, locale/fi/am, locale/fi/ap, + locale/fi/ar, locale/fi/arap, locale/fi/ca, locale/fi/cp, + locale/fi/ct, locale/fi/gl, locale/fi/ic, locale/fi/io, + locale/fi/ir, locale/fi/is, locale/fi/login, locale/fi/menu, + locale/fi/oe, locale/fi/pe, locale/fi/rc, locale/fi/rp, + locale/ua/COPYING, locale/ua/LANGUAGE, locale/ua/admin, + locale/ua/all, locale/ua/am, locale/ua/ap, locale/hu/COPYING, + locale/hu/LANGUAGE, locale/hu/admin, locale/hu/all, locale/hu/am, + locale/hu/ap, locale/ua/ar, locale/ua/arap, locale/ua/ca, + locale/ua/cp, locale/ua/ct, locale/ua/gl, locale/ua/ic, + locale/ua/io, locale/ua/ir, locale/ua/is, locale/ua/login, + locale/ua/menu, locale/ua/oe, locale/ua/pe, locale/ua/rc, + locale/ua/rp, locale/hu/ar, locale/hu/arap, locale/hu/ca, + locale/hu/cp, locale/hu/ct, locale/hu/gl, locale/hu/ic, + locale/hu/io, locale/hu/ir, locale/hu/is, locale/hu/login, + locale/hu/menu, locale/hu/oe, locale/hu/pe, locale/hu/rc, + locale/hu/rp, locale/is/COPYING, locale/is/LANGUAGE, + locale/is/all, locale/is/admin, locale/is/am, locale/is/ap, + locale/is/ar, locale/is/arap, locale/is/ca, locale/is/cp, + locale/is/ct, locale/is/gl, locale/is/ic, locale/is/io, + locale/is/ir, locale/is/is, locale/is/login, locale/is/menu, + locale/is/oe, locale/is/pe, locale/is/rc, locale/is/rp, + locale/ru/COPYING, locale/ru/LANGUAGE, locale/ru/all, + locale/ru/admin, locale/ru/am, locale/ru/ap, locale/ru/ar, + locale/ru/arap, locale/ru/ca, locale/ru/cp, locale/ru/ct, + locale/ru/gl, locale/ru/ic, locale/ru/io, locale/ru/ir, + locale/ru/is, locale/ru/login, locale/ru/menu, locale/ru/oe, + locale/ru/pe, locale/ru/rc, locale/ru/rp, locale/se/COPYING, + locale/se/LANGUAGE, locale/se/admin, locale/se/all, + locale/lt/COPYING, locale/lt/LANGUAGE, locale/lt/admin, + locale/lt/all, locale/se/am, locale/se/ap, locale/se/ar, + locale/se/arap, locale/se/ca, locale/se/cp, locale/se/ct, + locale/se/gl, locale/se/ic, locale/se/io, locale/se/ir, + locale/se/is, locale/se/login, locale/se/menu, locale/se/oe, + locale/se/pe, locale/se/rc, locale/se/rp, locale/en_GB/admin, + locale/en_GB/am, locale/en_GB/ap, locale/en_GB/ar, + locale/en_GB/ca, locale/en_GB/ct, locale/en_GB/gl, locale/lt/am, + locale/lt/ap, locale/lt/ar, locale/lt/arap, locale/lt/ca, + locale/lt/cp, locale/lt/ct, locale/lt/gl, locale/lt/ic, + locale/lt/io, locale/lt/ir, locale/lt/is, locale/lt/login, + locale/lt/menu, locale/lt/oe, locale/lt/pe, locale/lt/rc, + locale/lt/rp, locale/en_GB/COPYING, locale/en_GB/LANGUAGE, + locale/en_GB/all, locale/en_GB/arap, locale/en_GB/bp, + locale/en_GB/cp, locale/en_GB/ic, locale/en_GB/io, + locale/en_GB/ir, locale/en_GB/is, locale/en_GB/login, + locale/en_GB/menu, locale/en_GB/oe, locale/en_GB/pe, + locale/en_GB/rc, locale/en_GB/rp, sql/Default-chart.sql, + sql/Oracle-tables.sql, sql/Pg-tables.sql, sql/Canada-gifi.sql, + sql/Danish_Default-chart.sql, sql/Dutch_Default-chart.sql, + sql/France-chart.sql, sql/Italy-chart.sql, + sql/Oracle-indices.sql, sql/Pg-indices.sql, + sql/Pg-upgrade-1.6.0-1.8.0.sql, + sql/Simplified_Chinese_Default-chart.sql, sql/Spain-chart.sql, + sql/Traditional_Chinese_Default-chart.sql, sql/Austria-chart.sql, + sql/Austria-gifi.sql, sql/Canada_General-chart.sql, + sql/Czech_Republic-chart.sql, sql/Dutch_Standard-chart.sql, + sql/German-Sample-chart.sql, sql/German-Sample-gifi.sql, + sql/Oracle-upgrade-1.8.0-1.8.4.sql, + sql/Oracle-upgrade-1.8.4-1.8.5.sql, + sql/Pg-upgrade-1.2.6-1.2.7.sql, sql/Pg-upgrade-1.2.7-1.4.0.sql, + sql/Pg-upgrade-1.4.0-1.6.0.sql, sql/Pg-upgrade-1.8.0-1.8.4.sql, + sql/Pg-upgrade-1.8.4-1.8.5.sql, sql/Swiss-German-chart.sql, + sql/Swiss-German-gifi.sql, sql/US_General-chart.sql, + sql/Germany-DATEV-SKR03-gifi.sql, sql/Germany-SKR03-chart.sql, + sql/Germany-SKR03-gifi.sql, sql/Pg-upgrade-1.8.5-2.0.0.sql, + sql/Brazil_General-chart.sql, sql/Germany-DATEV-SKR03-chart.sql, + sql/Oracle-upgrade-1.8.5-2.0.0.sql, + sql/Oracle-upgrade-2.0.0-2.0.8.sql, + sql/Pg-upgrade-2.0.0-2.0.8.sql, sql/Poland-chart.sql, + templates/Danish-balance_sheet.html, + templates/Danish-income_statement.html, + templates/Danish-invoice.html, templates/Danish-invoice.tex, + templates/Danish-packing_list.html, + templates/Danish-packing_list.tex, + templates/Danish-purchase_order.html, + templates/Danish-purchase_order.tex, + templates/Danish-sales_order.html, + templates/Danish-sales_order.tex, + templates/Default-balance_sheet.html, + templates/Default-income_statement.html, + templates/Default-invoice.html, + templates/Estonian-balance_sheet.html, + templates/Estonian-income_statement.html, + templates/French-balance_sheet.html, + templates/French-income_statement.html, + templates/French-invoice.html, + templates/French-packing_list.html, + templates/Service-balance_sheet.html, + templates/Service-income_statement.html, + templates/Service-invoice.html, templates/Service-invoice.tex, + templates/Service-packing_list.html, + templates/Service-packing_list.tex, + templates/Service-purchase_order.tex, + templates/Service-sales_order.tex, + templates/Spanish_A4-balance_sheet.html, + templates/Spanish_A4-income_statement.html, + templates/Spanish_A4-invoice.html, + templates/Spanish_A4-invoice.tex, + templates/Spanish_A4-packing_list.html, + templates/Spanish_A4-packing_list.tex, + templates/Spanish_A4-purchase_order.html, + templates/Spanish_A4-purchase_order.tex, + templates/Spanish_A4-sales_order.html, + templates/Spanish_A4-sales_order.tex, + templates/Spanish_Letter-balance_sheet.html, + templates/Spanish_Letter-income_statement.html, + templates/Spanish_Letter-invoice.html, + templates/Spanish_Letter-invoice.tex, + templates/Spanish_Letter-packing_list.html, + templates/Spanish_Letter-packing_list.tex, + templates/Spanish_Letter-purchase_order.html, + templates/Spanish_Letter-purchase_order.tex, + templates/Spanish_Letter-sales_order.html, + templates/Spanish_Letter-sales_order.tex, users/members.default, + templates/Brazilian_Portuguese-check.tex, + templates/Danish-check.tex, templates/Danish-receipt.tex, + templates/Danish-statement.html, templates/Danish-statement.tex, + templates/Default-check.tex, templates/Default-invoice.tex, + templates/Default-packing_list.html, + templates/Default-packing_list.tex, + templates/Default-purchase_order.html, + templates/Default-purchase_order.tex, + templates/Default-receipt.tex, + templates/Default-sales_order.html, + templates/Default-sales_order.tex, + templates/Default-statement.html, + templates/Default-statement.tex, + templates/Dutch-balance_sheet.html, templates/Dutch-check.tex, + templates/Dutch-income_statement.html, + templates/Dutch-invoice.html, templates/Dutch-invoice.tex, + templates/Dutch-packing_list.html, + templates/Dutch-packing_list.tex, + templates/Dutch-purchase_order.html, + templates/Dutch-purchase_order.tex, templates/Dutch-receipt.tex, + templates/Dutch-sales_order.html, + templates/Dutch-sales_order.tex, templates/Dutch-statement.html, + templates/Dutch-statement.tex, templates/Estonian-check.tex, + templates/Estonian-invoice.html, templates/Estonian-invoice.tex, + templates/Estonian-packing_list.html, + templates/Estonian-packing_list.tex, + templates/Estonian-purchase_order.html, + templates/Estonian-purchase_order.tex, + templates/Estonian-receipt.tex, + templates/Estonian-sales_order.html, + templates/Estonian-sales_order.tex, + templates/Estonian-statement.html, + templates/Estonian-statement.tex, templates/French-check.tex, + templates/French-invoice.tex, templates/French-packing_list.tex, + templates/French-purchase_order.html, + templates/French-purchase_order.tex, + templates/French-receipt.tex, templates/French-sales_order.html, + templates/French-sales_order.tex, + templates/French-statement.html, templates/French-statement.tex, + templates/German-balance_sheet.html, templates/German-check.tex, + templates/German-income_statement.html, + templates/German-invoice.html, templates/German-invoice.tex, + templates/German-packing_list.html, + templates/German-packing_list.tex, + templates/German-purchase_order.html, + templates/German-purchase_order.tex, + templates/German-receipt.tex, templates/German-sales_order.html, + templates/German-sales_order.tex, + templates/German-statement.html, templates/German-statement.tex, + templates/Service-check.tex, + templates/Service-purchase_order.html, + templates/Service-receipt.tex, + templates/Service-sales_order.html, + templates/Service-statement.html, + templates/Service-statement.tex, templates/Spanish_A4-check.tex, + templates/Spanish_A4-receipt.tex, + templates/Spanish_A4-statement.html, + templates/Spanish_A4-statement.tex, + templates/Spanish_Letter-check.tex, + templates/Spanish_Letter-receipt.tex, + templates/Spanish_Letter-statement.html, + templates/Spanish_Letter-statement.tex, + templates/Brazilian_Portuguese-balance_sheet.html, + templates/Brazilian_Portuguese-income_statement.html, + templates/Brazilian_Portuguese-invoice.html, + templates/Brazilian_Portuguese-invoice.tex, + templates/Brazilian_Portuguese-packing_list.html, + templates/Brazilian_Portuguese-packing_list.tex, + templates/Brazilian_Portuguese-purchase_order.html, + templates/Brazilian_Portuguese-purchase_order.tex, + templates/Brazilian_Portuguese-receipt.tex, + templates/Brazilian_Portuguese-sales_order.html, + templates/Brazilian_Portuguese-sales_order.tex, + templates/Brazilian_Portuguese-statement.html, + templates/Brazilian_Portuguese-statement.tex: Initial revision + 2003-07-15 04:23 ivan * Makefile: 1.5.0pre3 @@ -23406,6 +27968,10 @@ * httemplate/view/cust_main.cgi: don't bother displaying comments that are only whitespace/newlines +2003-07-03 20:47 ivan + + * fs_signup/FS-SignupClient/cgi/stateselect.html: adding + 2003-07-03 20:34 ivan * etc/acp_logfile-parse: removing obsolete file @@ -23418,15 +27984,34 @@ * etc/example-direct-cardin: removing ancient cybercash example +2003-07-03 20:21 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: properly pass + init_popstate to error pages + +2003-07-03 20:12 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: add "initial_popstate" + option to signup server + +2003-07-03 18:54 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: don't add extra blank + pop + +2003-07-03 18:48 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: typo + 2003-07-03 18:37 ivan - * FS/FS/svc_acct_pop.pm: don't populate the whole initial list if - there are tons of POPs + * FS/FS/svc_acct_pop.pm, fs_signup/FS-SignupClient/cgi/signup.cgi: + don't populate the whole initial list if there are tons of POPs 2003-07-03 17:51 ivan - * FS/FS/svc_acct_pop.pm: optimize javascript to handle large - numbers of POPs + * FS/FS/svc_acct_pop.pm, fs_signup/FS-SignupClient/cgi/signup.cgi: + optimize javascript to handle large numbers of POPs 2003-07-03 16:00 ivan @@ -23438,8 +28023,9 @@ 2003-07-02 05:56 ivan - * FS/FS/part_pkg.pm: relaxed "first package" restrictions; will - find any appropriate service with quantity 1 + * FS/FS/part_pkg.pm, fs_signup/fs_signup_server: relaxed "first + package" restrictions; will find any appropriate service with + quantity 1 2003-07-02 05:34 ivan @@ -23502,6 +28088,12 @@ * FS/FS/part_export/forward_shellcommands.pm: forward_shellcommands update: might work now +2003-06-24 08:34 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: display full POP + numbers in signup server - patch from "Stephen Bechard" + + 2003-06-24 07:12 ivan * FS/FS/part_export/: forward_shellcommands.pm, sqlmail.pm: @@ -23873,9 +28465,36 @@ * httemplate/view/cust_main.cgi: Cleaned-up package view code and added CSS tags. +2003-05-09 00:17 ivan + + * install/freebsd/ports: mod_ssl before mod_perl so mod_perl picks + up EAPI + +2003-05-09 00:05 ivan + + * install/freebsd/: INSTALL, ports: little bit more fbsd install + automation + +2003-05-08 23:14 ivan + + * install/freebsd/INSTALL: freebsd install + 2003-05-08 23:03 ivan - * fs_selfservice/DEPLOY: updated freebsd install + * fs_selfservice/DEPLOY, install/freebsd/INSTALL, + install/freebsd/ports: updated freebsd install + +2003-05-08 18:18 ivan + + * install/freebsd/ports: Net::SSH and Net::SCP are in ports + +2003-05-08 17:10 ivan + + * install/redhat/7.3/: INSTALL, sources.list: redhat install foo + +2003-05-08 17:10 ivan + + * install/freebsd/: INSTALL, ports: automated install foo 2003-05-08 03:28 ivan @@ -24040,8 +28659,9 @@ * FS/FS/Conf.pm, FS/FS/cust_main.pm, FS/FS/part_bill_event.pm, FS/bin/freeside-daily, FS/bin/freeside-expiration-alerter, - FS/bin/freeside-setup, httemplate/docs/schema.html, - httemplate/edit/cust_main.cgi, + FS/bin/freeside-setup, fs_signup/FS-SignupClient/cgi/signup.cgi, + fs_signup/FS-SignupClient/cgi/signup.html, + httemplate/docs/schema.html, httemplate/edit/cust_main.cgi, httemplate/edit/part_bill_event.cgi, httemplate/edit/process/cust_main.cgi, httemplate/search/cust_main.cgi, httemplate/view/cust_main.cgi: @@ -24316,6 +28936,11 @@ * FS/bin/freeside-daily: declare $opt_p usage +2002-12-24 15:03 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: electronic checks work + in signup.cgi + 2002-12-24 14:41 ivan * README.1.5.0pre1, FS/bin/freeside-setup, @@ -24350,6 +28975,14 @@ selfservice_server-quiet, signup_server-quiet, and emailcancel messages. +2002-12-23 06:36 steve + + * fs_signup/: fs_signup_server, FS-SignupClient/SignupClient.pm: + added stuff for selfservice_server-quiet, signup_server-quiet, + and emailcancel messages. + + signup server can set user's comment field. + 2002-12-23 06:22 steve * FS/FS/: cust_bill.pm, Conf.pm: added stuff for @@ -24492,6 +29125,17 @@ * FS/FS/cust_bill.pm: empty invoice_lines() fix +2002-11-28 21:14 ivan + + * fs_signup/FS-SignupClient/cgi/signup.cgi: accept unmunged + state/county/country + +2002-11-28 02:54 ivan + + * fs_signup/: fs_signup_server, FS-SignupClient/cgi/signup.cgi, + FS-SignupClient/cgi/signup.html: separate state and country +