From d1154acfa526fa01d308be5d47a071643cfda5ea Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 25 Sep 2003 10:26:32 +0000 Subject: quiet self-service server cancels --- FS/FS/ClientAPI/MyAccount.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index e12e93b12..8d6f6e55a 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -245,7 +245,7 @@ sub cancel { my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) or return { 'error' => "unknown custnum $custnum" }; - my @errors = $cust_main->cancel; + my @errors = $cust_main->cancel( 'quiet'=>1 ); my $error = scalar(@errors) ? join(' / ', @errors) : ''; -- cgit v1.2.1 From daeb70ea28f8a3e0db500f8a0e107221f4542d30 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 25 Sep 2003 10:27:11 +0000 Subject: freebsd portability fixes --- FS/bin/freeside-selfservice-server | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/FS/bin/freeside-selfservice-server b/FS/bin/freeside-selfservice-server index 264cbc56d..6cfafda58 100644 --- a/FS/bin/freeside-selfservice-server +++ b/FS/bin/freeside-selfservice-server @@ -9,6 +9,7 @@ use strict; use vars qw( $Debug %kids $kids $max_kids $shutdown $log_file $ssh_pid ); +use subs qw( lock_write unlock_write ); use Fcntl qw(:flock); use POSIX qw(:sys_wait_h setsid); use IO::Handle; @@ -35,6 +36,9 @@ my $machine = shift or die &usage; my $pid_file = "/var/run/freeside-selfservice-server.$user.pid"; #my $pid_file = "/var/run/freeside-selfservice-server.$user.pid"; $FS::UID::datasrc not posible, but should include machine name at least, hmm +my $lock_file = "/usr/local/etc/freeside/selfservice.$machine.writelock"; +open(LOCKFILE,">$lock_file") or die "can't open $lock_file: $!"; + &init($user); my $conf = new FS::Conf; @@ -109,10 +113,10 @@ while (1) { $rv->{_token} = $packet->{_token}; #identifier warn "sending response\n" if $Debug; - flock($writer, LOCK_EX) or die "FATAL: can't lock write stream: $!"; + lock_write; nstore_fd($rv, $writer) or die "FATAL: can't send response: $!"; $writer->flush or die "FATAL: can't flush: $!"; - flock($writer, LOCK_UN) or die "WARNING: can't release write lock: $!"; + unlock_write; warn "child exiting\n" if $Debug; exit; #end-of-kid @@ -229,7 +233,23 @@ sub _do_logmsg { close $log; } +sub lock_write { + #broken on freebsd? + #flock($writer, LOCK_EX) or die "FATAL: can't lock write stream: $!"; + + flock(LOCKFILE, LOCK_EX) or die "FATAL: can't lock $lock_file: $!"; + +} + +sub unlock_write { + #broken on freebsd? + #flock($writer, LOCK_UN) or die "WARNING: can't release write lock: $!"; + + flock(LOCKFILE, LOCK_UN) or die "FATAL: can't unlock $lock_file: $!"; + +} + sub usage { - die "Usage:\n\n fs_signup_server user machine\n"; + die "Usage:\n\n freeside-selfservice-server user machine\n"; } -- cgit v1.2.1 From 9679b64218a5bb0b148d07582589dd8ef0de7567 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 25 Sep 2003 10:28:13 +0000 Subject: freebsd portability fix --- .../FS-SelfService/freeside-selfservice-clientd | 33 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/fs_selfservice/FS-SelfService/freeside-selfservice-clientd b/fs_selfservice/FS-SelfService/freeside-selfservice-clientd index f13dd42d7..438d472c9 100644 --- a/fs_selfservice/FS-SelfService/freeside-selfservice-clientd +++ b/fs_selfservice/FS-SelfService/freeside-selfservice-clientd @@ -5,7 +5,7 @@ # This is run REMOTELY over ssh by freeside-selfservice-server use strict; -use subs qw(spawn logmsg); +use subs qw(spawn logmsg lock_write unlock_write); use Fcntl qw(:flock); use POSIX qw(:sys_wait_h); use Socket; @@ -25,6 +25,8 @@ my $pid_file = "$socket.pid"; my $log_file = "/usr/local/freeside/selfservice.log"; +my $lock_file = "/usr/local/freeside/selfservice.writelock"; + #my $me = '[client]'; $|=1; @@ -35,6 +37,9 @@ $SIG{__WARN__} = \&_logmsg; #warn "$me Reading init data\n" if $Debug; #my $signup_init = +warn "Creating $lock_file\n" if $Debug; +open(LOCKFILE,">$lock_file") or die "can't open $lock_file: $!"; + warn "Creating $socket\n" if $Debug; my $uaddr = sockaddr_un($socket); my $proto = getprotobyname('tcp'); @@ -138,11 +143,19 @@ while (1) { #handle some commands weirdly? $packet->{_token}=$$; + warn "[child-$$] locking write stream" if $Debug > 1; + lock_write; + warn "[child-$$] sending packet to remote server" if $Debug > 1; - flock(STDOUT, LOCK_EX) or die "FATAL: can't lock write stream: $!"; nstore_fd($packet, \*STDOUT) or die "FATAL: can't send response: $!"; + + warn "[child-$$] flushing write stream" if $Debug > 1; STDOUT->flush or die "FATAL: can't flush: $!"; - flock(STDOUT, LOCK_UN) or die "FATAL: can't release write lock: $!"; + + warn "[child-$$] releasing write lock" if $Debug > 1; + unlock_write; + + warn "[child-$$] closing write stream" if $Debug > 1; close STDOUT or die "FATAL: can't close write stream: $!"; #??! warn "[child-$$] waiting for response from parent" if $Debug > 1; @@ -224,3 +237,17 @@ sub _logmsg { flock($log, LOCK_UN); close $log; } + +sub lock_write { + #broken on freebsd? + #flock(STDOUT, LOCK_EX) or die "FATAL: can't lock write stream: $!"; + + flock(LOCKFILE, LOCK_EX) or die "FATAL: can't lock $lock_file: $!"; +} + +sub unlock_write { + #broken on freebsd? + #flock(STDOUT, LOCK_UN) or die "FATAL: can't release write lock: $!"; + + flock(LOCKFILE, LOCK_UN) or die "FATAL: can't unlock $lock_file: $!"; +} -- cgit v1.2.1 From d6436c7251a94c9597c7b2195d63bd7c86f956e9 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 25 Sep 2003 10:42:28 +0000 Subject: add setuptax and recurtax fields to cust_main_county --- FS/bin/freeside-setup | 2 ++ httemplate/docs/schema.html | 2 ++ 2 files changed, 4 insertions(+) diff --git a/FS/bin/freeside-setup b/FS/bin/freeside-setup index 197542086..27d02529c 100755 --- a/FS/bin/freeside-setup +++ b/FS/bin/freeside-setup @@ -539,6 +539,8 @@ sub tables_hash_hack { 'exempt_amount', @money_type, 'tax', 'real', '', '', #tax % 'taxname', 'varchar', 'NULL', $char_d, + 'setuptax', 'char', 'NULL', 1, # Y = setup tax exempt + 'recurtax', 'char', 'NULL', 1, # Y = recur tax exempt ], 'primary_key' => 'taxnum', 'unique' => [], diff --git a/httemplate/docs/schema.html b/httemplate/docs/schema.html index a59755e76..9204bdc8f 100644 --- a/httemplate/docs/schema.html +++ b/httemplate/docs/schema.html @@ -142,6 +142,8 @@
  • taxclass
  • exempt_amount
  • taxname - if defined, printed on invoices instead of "Tax" +
  • setuptax - if 'Y', this tax does not apply to setup fees +
  • recurtax - if 'Y', this tax does not apply to recurring fees
  • cust_tax_exempt - Tax exemption record
      -- cgit v1.2.1 From 694627660388e33e0bab01a5571e660c930cb140 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 25 Sep 2003 11:17:06 +0000 Subject: multiple, named taxes for a single region 1.4 backport auto-adjusts based on schema --- FS/FS/cust_main.pm | 204 ++++++++++++++++++++++++++-------------------- FS/FS/cust_main_county.pm | 32 ++++++++ 2 files changed, 148 insertions(+), 88 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 700b100fb..385899387 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1134,7 +1134,6 @@ sub bill { warn "\$recur is undefined" unless defined($recur); warn "\$cust_pkg->bill is undefined" unless defined($cust_pkg->bill); - my $taxable_charged = 0; if ( $cust_pkg_mod_flag ) { $error=$cust_pkg->replace($old_cust_pkg); if ( $error ) { #just in case @@ -1163,86 +1162,94 @@ sub bill { push @cust_bill_pkg, $cust_bill_pkg; $total_setup += $setup; $total_recur += $recur; - $taxable_charged += $setup - unless $part_pkg->setuptax =~ /^Y$/i; - $taxable_charged += $recur - unless $part_pkg->recurtax =~ /^Y$/i; - - unless ( $self->tax =~ /Y/i - || $self->payby eq 'COMP' - || $taxable_charged == 0 ) { - - my $cust_main_county = qsearchs('cust_main_county',{ - 'state' => $self->state, - 'county' => $self->county, - 'country' => $self->country, - 'taxclass' => $part_pkg->taxclass, - } ); - $cust_main_county ||= qsearchs('cust_main_county',{ - 'state' => $self->state, - 'county' => $self->county, - 'country' => $self->country, - 'taxclass' => '', - } ); - unless ( $cust_main_county ) { + + unless ( $self->tax =~ /Y/i || $self->payby eq 'COMP' ) { + + my @taxes = qsearch( 'cust_main_county', { + 'state' => $self->state, + 'county' => $self->county, + 'country' => $self->country, + 'taxclass' => $part_pkg->taxclass, + } ) + || qsearch( 'cust_main_county', { + 'state' => $self->state, + 'county' => $self->county, + 'country' => $self->country, + 'taxclass' => '', + } ); + + # maybe eliminate this entirely, along with all the 0% records + unless ( @taxes ) { $dbh->rollback if $oldAutoCommit; return "fatal: can't find tax rate for state/county/country/taxclass ". join('/', ( map $self->$_(), qw(state county country) ), $part_pkg->taxclass ). "\n"; } + + foreach my $tax ( @taxes ) { + + my $taxable_charged = 0; + $taxable_charged += $setup + unless $part_pkg->setuptax =~ /^Y$/i + || $tax->setuptax =~ /^Y$/i; + $taxable_charged += $recur + unless $part_pkg->recurtax =~ /^Y$/i + || $tax->recurtax =~ /^Y$/i; + next unless $taxable_charged; + + if ( $tax->exempt_amount ) { + my ($mon,$year) = (localtime($sdate) )[4,5]; + $mon++; + my $freq = $part_pkg->freq || 1; + my $taxable_per_month = sprintf("%.2f", $taxable_charged / $freq ); + foreach my $which_month ( 1 .. $freq ) { + my %hash = ( + 'custnum' => $self->custnum, + 'taxnum' => $tax->taxnum, + 'year' => 1900+$year, + 'month' => $mon++, + ); + #until ( $mon < 12 ) { $mon -= 12; $year++; } + until ( $mon < 13 ) { $mon -= 12; $year++; } + my $cust_tax_exempt = + qsearchs('cust_tax_exempt', \%hash) + || new FS::cust_tax_exempt( { %hash, 'amount' => 0 } ); + my $remaining_exemption = sprintf("%.2f", + $tax->exempt_amount - $cust_tax_exempt->amount ); + if ( $remaining_exemption > 0 ) { + my $addl = $remaining_exemption > $taxable_per_month + ? $taxable_per_month + : $remaining_exemption; + $taxable_charged -= $addl; + my $new_cust_tax_exempt = new FS::cust_tax_exempt ( { + $cust_tax_exempt->hash, + 'amount' => + sprintf("%.2f", $cust_tax_exempt->amount + $addl), + } ); + $error = $new_cust_tax_exempt->exemptnum + ? $new_cust_tax_exempt->replace($cust_tax_exempt) + : $new_cust_tax_exempt->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "fatal: can't update cust_tax_exempt: $error"; + } + + } # if $remaining_exemption > 0 + + } #foreach $which_month + + } #if $tax->exempt_amount + + $taxable_charged = sprintf( "%.2f", $taxable_charged); + + #$tax += $taxable_charged * $cust_main_county->tax / 100 + $tax{ $tax->taxname || 'Tax' } += + $taxable_charged * $tax->tax / 100 - if ( $cust_main_county->exempt_amount ) { - my ($mon,$year) = (localtime($sdate) )[4,5]; - $mon++; - my $freq = $part_pkg->freq || 1; - my $taxable_per_month = sprintf("%.2f", $taxable_charged / $freq ); - foreach my $which_month ( 1 .. $freq ) { - my %hash = ( - 'custnum' => $self->custnum, - 'taxnum' => $cust_main_county->taxnum, - 'year' => 1900+$year, - 'month' => $mon++, - ); - #until ( $mon < 12 ) { $mon -= 12; $year++; } - until ( $mon < 13 ) { $mon -= 12; $year++; } - my $cust_tax_exempt = - qsearchs('cust_tax_exempt', \%hash) - || new FS::cust_tax_exempt( { %hash, 'amount' => 0 } ); - my $remaining_exemption = sprintf("%.2f", - $cust_main_county->exempt_amount - $cust_tax_exempt->amount ); - if ( $remaining_exemption > 0 ) { - my $addl = $remaining_exemption > $taxable_per_month - ? $taxable_per_month - : $remaining_exemption; - $taxable_charged -= $addl; - my $new_cust_tax_exempt = new FS::cust_tax_exempt ( { - $cust_tax_exempt->hash, - 'amount' => sprintf("%.2f", $cust_tax_exempt->amount + $addl), - } ); - $error = $new_cust_tax_exempt->exemptnum - ? $new_cust_tax_exempt->replace($cust_tax_exempt) - : $new_cust_tax_exempt->insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return "fatal: can't update cust_tax_exempt: $error"; - } - - } # if $remaining_exemption > 0 - - } #foreach $which_month - - } #if $cust_main_county->exempt_amount - - $taxable_charged = sprintf( "%.2f", $taxable_charged); - - #$tax += $taxable_charged * $cust_main_county->tax / 100 - $tax{ $cust_main_county->taxname || 'Tax' } += - $taxable_charged * $cust_main_county->tax / 100 - - } #unless $self->tax =~ /Y/i - # || $self->payby eq 'COMP' - # || $taxable_charged == 0 + } #foreach my $tax ( @taxes ) + + } #unless $self->tax =~ /Y/i || $self->payby eq 'COMP' } #if $setup > 0 || $recur > 0 @@ -1271,21 +1278,42 @@ sub bill { # $taxable_charged * ( $cust_main_county->getfield('tax') / 100 ) # ); - foreach my $taxname ( grep { $tax{$_} > 0 } keys %tax ) { - my $tax = sprintf("%.2f", $tax{$taxname} ); - $charged = sprintf( "%.2f", $charged+$tax ); - - my $cust_bill_pkg = new FS::cust_bill_pkg ({ - 'pkgnum' => 0, - 'setup' => $tax, - 'recur' => 0, - 'sdate' => '', - 'edate' => '', - 'itemdesc' => $taxname, - }); - push @cust_bill_pkg, $cust_bill_pkg; + if ( dbdef->table('cust_bill_pkg')->column('itemdesc') ) { #1.5 schema + + foreach my $taxname ( grep { $tax{$_} > 0 } keys %tax ) { + my $tax = sprintf("%.2f", $tax{$taxname} ); + $charged = sprintf( "%.2f", $charged+$tax ); + + my $cust_bill_pkg = new FS::cust_bill_pkg ({ + 'pkgnum' => 0, + 'setup' => $tax, + 'recur' => 0, + 'sdate' => '', + 'edate' => '', + 'itemdesc' => $taxname, + }); + push @cust_bill_pkg, $cust_bill_pkg; + } + + } else { #1.4 schema + + my $tax = 0; + foreach ( values %tax ) { $tax += $_ }; + $tax = sprintf("%.2f", $tax); + if ( $tax > 0 ) { + $charged = sprintf( "%.2f", $charged+$tax ); + + my $cust_bill_pkg = new FS::cust_bill_pkg ({ + 'pkgnum' => 0, + 'setup' => $tax, + 'recur' => 0, + 'sdate' => '', + 'edate' => '', + }); + push @cust_bill_pkg, $cust_bill_pkg; + } + } -# } my $cust_bill = new FS::cust_bill ( { 'custnum' => $self->custnum, diff --git a/FS/FS/cust_main_county.pm b/FS/FS/cust_main_county.pm index f631d8cae..76c982ae8 100644 --- a/FS/FS/cust_main_county.pm +++ b/FS/FS/cust_main_county.pm @@ -63,6 +63,10 @@ currently supported: =item taxname - if defined, printed on invoices instead of "Tax" +=item setuptax - if 'Y', this tax does not apply to setup fees + +=item recurtax - if 'Y', this tax does not apply to recurring fees + =back =head1 METHODS @@ -113,10 +117,38 @@ sub check { || $self->ut_textn('taxclass') # ... || $self->ut_money('exempt_amount') || $self->ut_textn('taxname') + || $self->ut_enum('setuptax', [ '', 'Y' ] ) + || $self->ut_enum('recurtax', [ '', 'Y' ] ) || $self->SUPER::check ; +} + +sub taxname { + my $self = shift; + if ( $self->dbdef_table->column('taxname') ) { + return $self->setfield('taxname', $_[0]) if @_; + return $self->getfield('taxname'); + } + return ''; +} + +sub setuptax { + my $self = shift; + if ( $self->dbdef_table->column('setuptax') ) { + return $self->setfield('setuptax', $_[0]) if @_; + return $self->getfield('setuptax'); + } + return ''; +} +sub recurtax { + my $self = shift; + if ( $self->dbdef_table->column('recurtax') ) { + return $self->setfield('recurtax', $_[0]) if @_; + return $self->getfield('recurtax'); + } + return ''; } =back -- cgit v1.2.1 From 4f253eb015531465e049c858a7520e8c7a71d227 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 25 Sep 2003 11:49:44 +0000 Subject: UI for multiple named taxes w/setup & recur exemptions 1.4 schema-auto-adjusting backport --- httemplate/browse/cust_main_county.cgi | 16 +++++++++++----- httemplate/edit/cust_main_county.cgi | 35 +++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/httemplate/browse/cust_main_county.cgi b/httemplate/browse/cust_main_county.cgi index c2473c4c8..e5827211c 100755 --- a/httemplate/browse/cust_main_county.cgi +++ b/httemplate/browse/cust_main_county.cgi @@ -24,7 +24,7 @@ print '

      '. &table(). <Taxclass
      (per-package classification) Tax name
      (printed on invoices) Tax - Exempt
      per
      month + Exemption END @@ -54,7 +54,9 @@ END last if $hashref->{country} ne $regions[$i+$j]->country || $hashref->{state} ne $regions[$i+$j]->state || $hashref->{tax} != $regions[$i+$j]->tax - || $hashref->{exempt_amount} != $regions[$i+$j]->exempt_amount; + || $hashref->{exempt_amount} != $regions[$i+$j]->exempt_amount + || $hashref->{setuptax} ne $regions[$i+$j]->setuptax + || $hashref->{recurtax} ne $regions[$i+$j]->recurtax; } my $newsup=0; @@ -121,9 +123,13 @@ END print ""; print "$hashref->{tax}%". - '$'. - sprintf("%.2f", $hashref->{exempt_amount} || 0). ''. - ''; + ''; + print '$'. sprintf("%.2f", $hashref->{exempt_amount} ). + ' per month
      ' + if $hashref->{exempt_amount}; + print 'Setup fee
      ' if $hashref->{setuptax} =~ /^Y$/i; + print 'Recurring fee
      ' if $hashref->{recurtax} =~ /^Y$/i; + print ''; } diff --git a/httemplate/edit/cust_main_county.cgi b/httemplate/edit/cust_main_county.cgi index f3d28825a..efc12f3e0 100755 --- a/httemplate/edit/cust_main_county.cgi +++ b/httemplate/edit/cust_main_county.cgi @@ -16,12 +16,26 @@ print qq!
      "; print qq!!; + qq!" VALUE="!, $hashref->{taxname}, qq!">! + if dbdef->table('cust_main_county')->column('taxname'); + print qq!%!; print qq!\$!; + + print qq!{setuptax} =~ /^Y$/i ? ' CHECKED' : '' ). + '">' + if dbdef->table('cust_main_county')->column('setuptax'); + + print qq!{recurtax} =~ /^Y$/i ? ' CHECKED' : '' ). + '">' + if dbdef->table('cust_main_county')->column('recurtax'); + print ''; } -- cgit v1.2.1 From 32508fdce66413a5f26c5d5f755121451fb734d6 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 25 Sep 2003 11:56:47 +0000 Subject: new per-tax setuptax and recurtax fields --- httemplate/docs/upgrade10.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/httemplate/docs/upgrade10.html b/httemplate/docs/upgrade10.html index d7a8c7468..253ea891d 100644 --- a/httemplate/docs/upgrade10.html +++ b/httemplate/docs/upgrade10.html @@ -68,6 +68,10 @@ ALTER TABLE cust_bill_pkg ADD itemdesc varchar(80) NULL; ALTER TABLE h_cust_bill_pkg ADD itemdesc varchar(80) NULL; ALTER TABLE cust_main_county ADD taxname varchar(80) NULL; ALTER TABLE h_cust_main_county ADD taxname varchar(80) NULL; +ALTER TABLE cust_main_county ADD setuptax char(1) NULL; +ALTER TABLE h_cust_main_county ADD setuptax char(1) NULL; +ALTER TABLE cust_main_county ADD recurtax char(1) NULL; +ALTER TABLE h_cust_main_county ADD recurtax char(1) NULL; ALTER TABLE cust_pkg ADD last_bill int NULL; ALTER TABLE h_cust_pkg ADD last_bill int NULL; -- cgit v1.2.1 From bfe2b53779bd76e03aa8deaca07ba916da6b3f5b Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 26 Sep 2003 08:11:12 +0000 Subject: fix tax edit UI --- httemplate/browse/cust_main_county.cgi | 2 +- httemplate/edit/cust_main_county.cgi | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/httemplate/browse/cust_main_county.cgi b/httemplate/browse/cust_main_county.cgi index e5827211c..1e0e0880c 100755 --- a/httemplate/browse/cust_main_county.cgi +++ b/httemplate/browse/cust_main_county.cgi @@ -126,7 +126,7 @@ END ''; print '$'. sprintf("%.2f", $hashref->{exempt_amount} ). ' per month
      ' - if $hashref->{exempt_amount}; + if $hashref->{exempt_amount} > 0; print 'Setup fee
      ' if $hashref->{setuptax} =~ /^Y$/i; print 'Recurring fee
      ' if $hashref->{recurtax} =~ /^Y$/i; print ''; diff --git a/httemplate/edit/cust_main_county.cgi b/httemplate/edit/cust_main_county.cgi index efc12f3e0..4bcfcbe9b 100755 --- a/httemplate/edit/cust_main_county.cgi +++ b/httemplate/edit/cust_main_county.cgi @@ -65,21 +65,21 @@ END qq!" VALUE="!, $hashref->{taxname}, qq!">! if dbdef->table('cust_main_county')->column('taxname'); - print qq!%!; - print qq!\$!; + print qq!
      %
      !; + print qq!
      \$
      !; print qq!{setuptax} =~ /^Y$/i ? ' CHECKED' : '' ). - '">' + '>' if dbdef->table('cust_main_county')->column('setuptax'); print qq!{recurtax} =~ /^Y$/i ? ' CHECKED' : '' ). - '">' + '>' if dbdef->table('cust_main_county')->column('recurtax'); print ''; -- cgit v1.2.1 From 2d82b5b713c7c11d2d54a018d121b80fd6485c60 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 26 Sep 2003 09:09:08 +0000 Subject: fix manual_flag problem preventing cust_pkg editing --- FS/FS/cust_pkg.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 1bf56e128..d9a6385e2 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -244,7 +244,9 @@ sub check { $self->otaker($1); if ( $self->dbdef_table->column('manual_flag') ) { - $self->manual_flag =~ /^([01]?)$/ or return "Illegal manual_flag"; + $self->manual_flag('') if $self->manual_flag eq ' '; + $self->manual_flag =~ /^([01]?)$/ + or return "Illegal manual_flag ". $self->manual_flag; $self->manual_flag($1); } -- cgit v1.2.1 From 6621bcd8966b784ff930c51548432a15e8094e94 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 26 Sep 2003 09:15:33 +0000 Subject: re-enable ChopBlanks for now --- FS/FS/UID.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm index f67005151..8271f89f2 100644 --- a/FS/FS/UID.pm +++ b/FS/FS/UID.pm @@ -87,7 +87,7 @@ sub forksuidsetup { getsecrets; $dbh = DBI->connect($datasrc,$db_user,$db_pass, { 'AutoCommit' => 0, - #'ChopBlanks' => 1, + 'ChopBlanks' => 1, } ) or die "DBI->connect error: $DBI::errstr\n"; foreach ( keys %callback ) { -- cgit v1.2.1 From b0fb4547e39f3ad26bedb95d8cc8b5a10f66a4eb Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 26 Sep 2003 09:31:11 +0000 Subject: scalar/array scope fix... new, multiple (i.e. canadian GST/PST) taxes work now! --- FS/FS/cust_main.pm | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 385899387..90cf18e8f 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1165,18 +1165,20 @@ sub bill { unless ( $self->tax =~ /Y/i || $self->payby eq 'COMP' ) { - my @taxes = qsearch( 'cust_main_county', { - 'state' => $self->state, - 'county' => $self->county, - 'country' => $self->country, - 'taxclass' => $part_pkg->taxclass, - } ) - || qsearch( 'cust_main_county', { + my @taxes = qsearch( 'cust_main_county', { + 'state' => $self->state, + 'county' => $self->county, + 'country' => $self->country, + 'taxclass' => $part_pkg->taxclass, + } ); + unless ( @taxes ) { + @taxes = qsearch( 'cust_main_county', { 'state' => $self->state, 'county' => $self->county, 'country' => $self->country, 'taxclass' => '', } ); + } # maybe eliminate this entirely, along with all the 0% records unless ( @taxes ) { -- cgit v1.2.1 From 74e6f7cb1f048778a417e0124143f6c447c9f87c Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 26 Sep 2003 13:04:26 +0000 Subject: re-setup option to re-charge setup fee --- FS/FS/cust_main.pm | 16 ++++++++++------ FS/bin/freeside-daily | 11 +++++++---- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 90cf18e8f..de22ab5c5 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -993,15 +993,19 @@ conjunction with the collect method. Options are passed as name-value pairs. -The only currently available option is `time', which bills the customer as if -it were that time. It is specified as a UNIX timestamp; see -L). Also see L and L for conversion -functions. For example: +Currently available options are: + +resetup - if set true, re-charges setup fees. + +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') ); + If there is an error, returns the error, otherwise returns false. =cut @@ -1058,7 +1062,7 @@ sub bill { # bill setup my $setup = 0; - unless ( $cust_pkg->setup ) { + if ( !$cust_pkg->setup || $options{'resetup'} ) { my $setup_prog = $part_pkg->getfield('setup'); $setup_prog =~ /^(.*)$/ or do { $dbh->rollback if $oldAutoCommit; @@ -1078,7 +1082,7 @@ sub bill { return "Error eval-ing part_pkg->setup pkgpart ". $part_pkg->pkgpart. "(expression $setup_prog): $@"; } - $cust_pkg->setfield('setup',$time); + $cust_pkg->setfield('setup', $time) unless $cust_pkg->setup; $cust_pkg_mod_flag=1; } diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily index 63e621b57..80b8edf82 100755 --- a/FS/bin/freeside-daily +++ b/FS/bin/freeside-daily @@ -10,8 +10,8 @@ use FS::Conf; use FS::cust_main; &untaint_argv; #what it sounds like (eww) -use vars qw($opt_d $opt_v $opt_p); -getopts("p:d:v"); +use vars qw($opt_d $opt_v $opt_p $opt_s); +getopts("p:d:vs"); my $user = shift or die &usage; adminsuidsetup $user; @@ -42,7 +42,8 @@ foreach $cust_main ( @cust_main ) { if $error; } - my $error = $cust_main->bill( 'time' => $time ); + my $error = $cust_main->bill( 'time' => $time, + 'resetup' => $opt_s, ); warn "Error billing, custnum ". $cust_main->custnum. ": $error" if $error; $cust_main->apply_payments; @@ -98,7 +99,7 @@ freeside-daily - Run daily billing and invoice collection events. =head1 SYNOPSIS - freeside-daily [ -d 'date' ] [ -p 'payby' ] [ -v ] user [ custnum custnum ... ] + freeside-daily [ -d 'date' ] [ -p 'payby' ] [ -s ] [ -v ] user [ custnum custnum ... ] =head1 DESCRIPTION @@ -115,6 +116,8 @@ the bill and collect methods of a cust_main object. See L. -p: Only process customers with the specified payby (I, I, I, I, I, I, I) + -s: re-charge setup fees + -v: enable debugging user: From the mapsecrets file - see config.html from the base documentation -- cgit v1.2.1 From 056a0e2da67602762263e66b30d3226007355318 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 26 Sep 2003 13:37:24 +0000 Subject: sql --- httemplate/docs/upgrade10.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/docs/upgrade10.html b/httemplate/docs/upgrade10.html index 253ea891d..2f7f4d89a 100644 --- a/httemplate/docs/upgrade10.html +++ b/httemplate/docs/upgrade10.html @@ -62,7 +62,7 @@ CREATE TABLE svc_broadband ( PRIMARY KEY (svcnum) ); -DELETE INDEX cust_bill_pkg1; +DROP INDEX cust_bill_pkg1; ALTER TABLE cust_bill_pkg ADD itemdesc varchar(80) NULL; ALTER TABLE h_cust_bill_pkg ADD itemdesc varchar(80) NULL; -- cgit v1.2.1 From 8bf17cd5daed65822e577b60794a4398e5e3dd2d Mon Sep 17 00:00:00 2001 From: khoff Date: Fri, 26 Sep 2003 21:02:13 +0000 Subject: $field isn't a global. --- 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 44606d9a0..f1b8b800b 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -281,7 +281,7 @@ if ( $part_svc->part_svc_column('usergroup')->columnflag eq "F" ) { } print ''; -foreach $field ($svc_acct->virtual_fields) { +foreach my $field ($svc_acct->virtual_fields) { if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) { # If the flag is X, it won't even show up in $svc_acct->virtual_fields. print $svc_acct->pvf($field)->widget('HTML', 'edit', -- cgit v1.2.1 From c2a0b1b8e9d437434e326a3b573d7134c5697213 Mon Sep 17 00:00:00 2001 From: khoff Date: Fri, 26 Sep 2003 23:33:09 +0000 Subject: $field is not a global. --- httemplate/edit/svc_www.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/svc_www.cgi b/httemplate/edit/svc_www.cgi index 043af610b..ec5169e05 100644 --- a/httemplate/edit/svc_www.cgi +++ b/httemplate/edit/svc_www.cgi @@ -167,7 +167,7 @@ foreach $_ (keys %username) { } print ""; -foreach $field ($svc_www->virtual_fields) { +foreach my $field ($svc_www->virtual_fields) { if ( $part_svc->part_svc_column($field)->columnflag ne 'F' ) { # If the flag is X, it won't even show up in $svc_acct->virtual_fields. print $svc_www->pvf($field)->widget('HTML', 'edit', -- cgit v1.2.1 From c8f80bd5aaeb0f3844a7cece4bfe250d4f89f745 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 28 Sep 2003 02:36:18 +0000 Subject: add upload of batch result from TD Canada Trust some global.asa / handler.pl enhancements --- FS/FS/cust_pay_batch.pm | 138 ++++++++++++++++++++++++++++++++++- htetc/global.asa | 32 ++++++++ htetc/handler.pl | 47 ++++++++---- httemplate/browse/cust_pay_batch.cgi | 13 +++- httemplate/misc/upload-batch.cgi | 28 +++++++ 5 files changed, 239 insertions(+), 19 deletions(-) create mode 100644 httemplate/misc/upload-batch.cgi diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm index 1a530467c..97c168159 100644 --- a/FS/FS/cust_pay_batch.pm +++ b/FS/FS/cust_pay_batch.pm @@ -2,7 +2,7 @@ package FS::cust_pay_batch; use strict; use vars qw( @ISA ); -use FS::Record; +use FS::Record qw(dbh qsearchs); use Business::CreditCard; @ISA = qw( FS::Record ); @@ -190,9 +190,141 @@ sub check { =back -=head1 VERSION +=head1 SUBROUTINES -$Id: cust_pay_batch.pm,v 1.7 2003-08-05 00:20:42 khoff Exp $ +=over 4 + +=item import_results + +=cut + +sub import_results { + use Time::Local; + use FS::cust_pay; + eval "use Text::CSV_XS;"; + die $@ if $@; +# + my $param = shift; + my $fh = $param->{'filehandle'}; + my $format = $param->{'format'}; + my $paybatch = $param->{'paybatch'}; + + my @fields; + my $condition; + my $hook; + + if ( $format eq 'csv-td_canada_trust-merchant_pc_batch' ) { + + @fields = ( + 'paybatchnum', # Reference#: Invoice number of the transaction + 'paid', # Amount: Amount of the transaction. Dollars and cents + # with no decimal entered. + '', # Card Type: 0 - MCrd, 1 - Visa, 2 - AMEX, 3 - Discover, + # 4 - Insignia, 5 - Diners/EnRoute, 6 - JCB + '_date', # Transaction Date: Date the Transaction was processed + 'time', # Transaction Time: Time the transaction was processed + 'payinfo', # Card Number: Card number for the transaction + '', # Expiry Date: Expiry date of the card + '', # Auth#: Authorization number entered for force post + # transaction + 'type', # Transaction Type: 0 - purchase, 40 - refund, + # 20 - force post + 'result', # Processing Result: 3 - Approval, + # 4 - Declined/Amount over limit, + # 5 - Invalid/Expired/stolen card, + # 6 - Comm Error + '', # Terminal ID: Terminal ID used to process the transaction + ); + + $condition = sub { + my $hash = shift; + $hash->{'result'} == 3 && $hash->{'type'} == 0; + }; + + $hook = sub { + my $hash = shift; + $hash->{'paid'} = sprintf("%.2f", $hash->{'paid'} / 100 ); + $hash->{'_date'} = timelocal( substr($hash->{'time'}, 4, 2), + substr($hash->{'time'}, 2, 2), + substr($hash->{'time'}, 0, 2), + substr($hash->{'_date'}, 6, 2), + substr($hash->{'_date'}, 4, 2)-1, + substr($hash->{'_date'}, 0, 4)-1900, ); + }; + + } else { + return "Unknown format $format"; + } + + my $csv = new Text::CSV_XS; + + 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 $line; + while ( defined($line=<$fh>) ) { + + $csv->parse($line) or do { + $dbh->rollback if $oldAutoCommit; + return "can't parse: ". $csv->error_input(); + }; + + my @values = $csv->fields(); + my %hash; + foreach my $field ( @fields ) { + my $value = shift @values; + next unless $field; + $hash{$field} = $value; + } + + my $cust_pay_batch = + qsearchs('cust_pay_batch', { 'paybatchnum' => $hash{'paybatchnum'} } ); + unless ( $cust_pay_batch ) { + $dbh->rollback if $oldAutoCommit; + return "unknown paybatchnum $hash{'paybatchnum'}\n"; + } + my $custnum = $cust_pay_batch->custnum, + + my $error = $cust_pay_batch->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error removing paybatchnum $hash{'paybatchnum'}: $error\n"; + } + + next unless &{$condition}(\%hash); + + &{$hook}(\%hash); + + my $cust_pay = new FS::cust_pay ( { + 'custnum' => $custnum, + 'payby' => 'CARD', + 'paybatch' => $paybatch, + map { $_ => $hash{$_} } (qw( paid _date payinfo )), + } ); + $error = $cust_pay->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error adding payment paybatchnum $hash{'paybatchnum'}: $error\n"; + } + + $cust_pay->cust_main->apply_payments; + + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + +=back =head1 BUGS diff --git a/htetc/global.asa b/htetc/global.asa index 5b0ac4991..f00ae57f5 100644 --- a/htetc/global.asa +++ b/htetc/global.asa @@ -9,6 +9,7 @@ use CGI; use Date::Format; use Date::Parse; use Time::Local; +use File::Basename; use Tie::IxHash; use HTML::Entities; use IO::Handle; @@ -195,5 +196,36 @@ sub include { $Response->Include(@_); } +if ( defined(@DBIx::Profile::ISA) ) { + + #false laziness w/above + *redirect = sub { + my($location) = @_; + + ${$Response->{BinaryRef}} = + $cgi->header. + qq!Redirect to $location!. + '

      '.
      +        ( UNIVERSAL::can(dbh, 'sprintProfile')
      +            ? encode_entities(dbh->sprintProfile())
      +            : 'DBIx::Profile missing sprintProfile method;'.
      +              'unpatched or too old?'                        ).
      +      "\n\n". &sprintAutoProfile().  '
      '. + ''; + + dbh->{'private_profile'} = {}; + + $Response->End; + + }; + +} else { + + *redirect = sub { + $Response->Redirect(@_); + } + +} + 1; diff --git a/htetc/handler.pl b/htetc/handler.pl index 8f079af33..1660cb3fa 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -67,6 +67,7 @@ sub handler use Date::Format; use Date::Parse; use Time::Local; + use File::Basename; use Tie::IxHash; use HTML::Entities; use IO::Handle; @@ -141,20 +142,10 @@ sub handler } else { #normal redirect - #http://www.masonhq.com/docs/faq/#how_do_i_do_an_external_redirect - $m->clear_buffer; - # The next two lines are necessary to stop Apache from re-reading - # POSTed data. - $r->method('GET'); - $r->headers_in->unset('Content-length'); - $r->content_type('text/html'); - #$r->err_header_out('Location' => $location); - $r->header_out('Location' => $location); - $r->header_out('Content-Type' => 'text/html'); - $m->abort(302); - + $m->redirect($location); ''; - } + + } }; @@ -168,6 +159,36 @@ sub handler $m->scomp(@_); } + sub redirect { + my( $location ) = @_; + use vars qw($m); + $m->clear_buffer; + #false laziness w/above + if ( defined(@DBIx::Profile::ISA) ) { #profiling redirect + + $m->print( + qq!Redirect to $location!. + '

      '.
      +              ( UNIVERSAL::can(dbh, 'sprintProfile')
      +                  ? encode_entities(dbh->sprintProfile())
      +                  : 'DBIx::Profile missing sprintProfile method;'.
      +                    'unpatched or too old?'                        ).
      +            #"\n\n". &sprintAutoProfile().  '
      '. + "\n\n". ''. + '' + ); + dbh->{'private_profile'} = {}; + + $m->abort(200); + + } else { #normal redirect + + $m->redirect($location); + + } + + } + } # end package HTML::Mason::Commands; $r->content_type('text/html'); diff --git a/httemplate/browse/cust_pay_batch.cgi b/httemplate/browse/cust_pay_batch.cgi index f9d0921a1..d90a03313 100755 --- a/httemplate/browse/cust_pay_batch.cgi +++ b/httemplate/browse/cust_pay_batch.cgi @@ -2,11 +2,18 @@ <%= header("Pending credit card batch", menubar( 'Main Menu' => $p,)) %> - Download batch in format + +

      + +
      +Upload results
      +Filename
      +Format
      +


      <%= &table() %> diff --git a/httemplate/misc/upload-batch.cgi b/httemplate/misc/upload-batch.cgi new file mode 100644 index 000000000..565a6da5c --- /dev/null +++ b/httemplate/misc/upload-batch.cgi @@ -0,0 +1,28 @@ +<% + + my $fh = $cgi->upload('batch_results'); + my $filename = $cgi->param('batch_results'); + my $paybatch = basename($filename); + + my $error = defined($fh) + ? FS::cust_pay_batch::import_results( { + 'filehandle' => $fh, + 'format' => $cgi->param('format'), + 'paybatch' => $paybatch, + } ) + : 'No file'; + + if ( $error ) { + %> + + <% + eidiot($error); +# $cgi->param('error', $error); +# print $cgi->redirect( "${p}cust_main-import.cgi + } else { + %> + + <%= header('Batch results upload sucessful') %> <% + } +%> + -- cgit v1.2.1