From fbcb45dfe5a1bce7981fe4527176b9fdf2ec54b7 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 3 Sep 2001 22:07:39 +0000 Subject: [PATCH] fix more bugs --- FS/FS/cust_bill.pm | 4 +- FS/FS/cust_bill_pay.pm | 4 +- FS/FS/cust_main.pm | 169 ++++++++++++++++++++++------------- FS/FS/cust_pay.pm | 31 ++++--- FS/FS/cust_svc.pm | 4 +- FS/bin/freeside-bill | 19 ++-- httemplate/docs/signup.html | 2 +- httemplate/docs/upgrade8.html | 30 ++++++- httemplate/edit/cust_credit.cgi | 14 ++- httemplate/edit/cust_credit_bill.cgi | 66 ++++++++++---- httemplate/edit/cust_pay.cgi | 33 +++++-- httemplate/edit/process/cust_pay.cgi | 26 ++++-- httemplate/misc/bill.cgi | 5 +- httemplate/view/cust_bill.cgi | 12 ++- httemplate/view/cust_main.cgi | 59 +++++++----- 15 files changed, 321 insertions(+), 157 deletions(-) diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 2ca4b529a..f61137f54 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -408,7 +408,7 @@ sub print_text { push @buf,[ "Payment received ". time2str("%x",$_->cust_pay->_date ), - $money_char. sprintf("%10.2f",$_->paid ) + $money_char. sprintf("%10.2f",$_->amount ) ]; } @@ -489,7 +489,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.10 2001-09-02 01:27:10 ivan Exp $ +$Id: cust_bill.pm,v 1.11 2001-09-03 22:07:38 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_bill_pay.pm b/FS/FS/cust_bill_pay.pm index 921c0255c..5ef82d658 100644 --- a/FS/FS/cust_bill_pay.pm +++ b/FS/FS/cust_bill_pay.pm @@ -114,7 +114,7 @@ sub insert { if ( $bill_total > $cust_bill->charged ) { $dbh->rollback if $oldAutoCommit; return "total cust_bill_pay.amount and cust_credit_bill.amount $bill_total". - "for invnum ". $self->invnum. + " for invnum ". $self->invnum. " greater than cust_bill.charged ". $cust_bill->charged; } @@ -195,7 +195,7 @@ sub cust_bill { =head1 VERSION -$Id: cust_bill_pay.pm,v 1.7 2001-09-02 07:49:52 ivan Exp $ +$Id: cust_bill_pay.pm,v 1.8 2001-09-03 22:07:38 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 41ad21b72..b29e3852b 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -709,10 +709,16 @@ sub ncancelled_pkgs { Generates invoices (see L) for this customer. Usually used in 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. +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. @@ -740,7 +746,7 @@ sub bill { # & generate invoice database. my( $total_setup, $total_recur ) = ( 0, 0 ); - my @cust_bill_pkg; + my @cust_bill_pkg = (); foreach my $cust_pkg ( qsearch('cust_pkg',{'custnum'=> $self->getfield('custnum') } ) @@ -763,20 +769,24 @@ sub bill { my $setup = 0; unless ( $cust_pkg->setup ) { my $setup_prog = $part_pkg->getfield('setup'); - $setup_prog =~ /^(.*)$/ #presumably trusted - or die "Illegal setup for package ". $cust_pkg->pkgnum. ": $setup_prog"; + $setup_prog =~ /^(.*)$/ or do { + $dbh->rollback if $oldAutoCommit; + return "Illegal setup for pkgpart ". $part_pkg->pkgpart. + ": $setup_prog"; + }; $setup_prog = $1; + my $cpt = new Safe; #$cpt->permit(); #what is necessary? $cpt->share(qw( $cust_pkg )); #can $cpt now use $cust_pkg methods? $setup = $cpt->reval($setup_prog); unless ( defined($setup) ) { - warn "Error reval-ing part_pkg->setup pkgpart ", - $part_pkg->pkgpart, ": $@"; - } else { - $cust_pkg->setfield('setup',$time); - $cust_pkg_mod_flag=1; + $dbh->rollback if $oldAutoCommit; + return "Error reval-ing part_pkg->setup pkgpart ". $part_pkg->pkgpart. + ": $@"; } + $cust_pkg->setfield('setup',$time); + $cust_pkg_mod_flag=1; } #bill recurring fee @@ -787,43 +797,57 @@ sub bill { ( $cust_pkg->getfield('bill') || 0 ) < $time ) { my $recur_prog = $part_pkg->getfield('recur'); - $recur_prog =~ /^(.*)$/ #presumably trusted - or die "Illegal recur for package ". $cust_pkg->pkgnum. ": $recur_prog"; + $recur_prog =~ /^(.*)$/ or do { + $dbh->rollback if $oldAutoCommit; + return "Illegal recur for pkgpart ". $part_pkg->pkgpart. + ": $recur_prog"; + }; $recur_prog = $1; + my $cpt = new Safe; #$cpt->permit(); #what is necessary? $cpt->share(qw( $cust_pkg )); #can $cpt now use $cust_pkg methods? $recur = $cpt->reval($recur_prog); unless ( defined($recur) ) { - warn "Error reval-ing part_pkg->recur pkgpart ", - $part_pkg->pkgpart, ": $@"; - } else { - #change this bit to use Date::Manip? CAREFUL with timezones (see - # mailing list archive) - #$sdate=$cust_pkg->bill || time; - #$sdate=$cust_pkg->bill || $time; - $sdate = $cust_pkg->bill || $cust_pkg->setup || $time; - my ($sec,$min,$hour,$mday,$mon,$year) = - (localtime($sdate) )[0,1,2,3,4,5]; - $mon += $part_pkg->getfield('freq'); - until ( $mon < 12 ) { $mon -= 12; $year++; } - $cust_pkg->setfield('bill', - timelocal($sec,$min,$hour,$mday,$mon,$year)); - $cust_pkg_mod_flag = 1; + $dbh->rollback if $oldAutoCommit; + return "Error reval-ing part_pkg->recur pkgpart ". + $part_pkg->pkgpart. ": $@"; } + #change this bit to use Date::Manip? CAREFUL with timezones (see + # mailing list archive) + #$sdate=$cust_pkg->bill || time; + #$sdate=$cust_pkg->bill || $time; + $sdate = $cust_pkg->bill || $cust_pkg->setup || $time; + my ($sec,$min,$hour,$mday,$mon,$year) = + (localtime($sdate) )[0,1,2,3,4,5]; + $mon += $part_pkg->getfield('freq'); + until ( $mon < 12 ) { $mon -= 12; $year++; } + $cust_pkg->setfield('bill', + timelocal($sec,$min,$hour,$mday,$mon,$year)); + $cust_pkg_mod_flag = 1; } - warn "setup is undefined" unless defined($setup); - warn "recur is undefined" unless defined($recur); - warn "cust_pkg bill is undefined" unless defined($cust_pkg->bill); + warn "\$setup is undefined" unless defined($setup); + warn "\$recur is undefined" unless defined($recur); + warn "\$cust_pkg->bill is undefined" unless defined($cust_pkg->bill); if ( $cust_pkg_mod_flag ) { $error=$cust_pkg->replace($old_cust_pkg); if ( $error ) { #just in case - warn "Error modifying pkgnum ", $cust_pkg->pkgnum, ": $error"; - } else { - $setup = sprintf( "%.2f", $setup ); - $recur = sprintf( "%.2f", $recur ); + $dbh->rollback if $oldAutoCommit; + return "Error modifying pkgnum ". $cust_pkg->pkgnum. ": $error"; + } + $setup = sprintf( "%.2f", $setup ); + $recur = sprintf( "%.2f", $recur ); + if ( $setup < 0 ) { + $dbh->rollback if $oldAutoCommit; + return "negative setup $setup for pkgnum ". $cust_pkg->pkgnum; + } + if ( $recur < 0 ) { + $dbh->rollback if $oldAutoCommit; + return "negative recur $recur for pkgnum ". $cust_pkg->pkgnum; + } + if ( $setup > 0 || $recur > 0 ) { my $cust_bill_pkg = new FS::cust_bill_pkg ({ 'pkgnum' => $cust_pkg->pkgnum, 'setup' => $setup, @@ -844,11 +868,9 @@ sub bill { unless ( @cust_bill_pkg ) { $dbh->commit or die $dbh->errstr if $oldAutoCommit; return ''; - } + } - unless ( $self->getfield('tax') =~ /Y/i - || $self->getfield('payby') eq 'COMP' - ) { + unless ( $self->tax =~ /Y/i || $self->payby eq 'COMP' ) { my $cust_main_county = qsearchs('cust_main_county',{ 'state' => $self->state, 'county' => $self->county, @@ -870,25 +892,25 @@ sub bill { } my $cust_bill = new FS::cust_bill ( { - 'custnum' => $self->getfield('custnum'), - '_date' => $time, + 'custnum' => $self->custnum, + '_date' => $time, 'charged' => $charged, } ); $error = $cust_bill->insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; - return "$error for customer #". $self->custnum; + return "can't create invoice for customer #". $self->custnum. ": $error"; } my $invnum = $cust_bill->invnum; my $cust_bill_pkg; foreach $cust_bill_pkg ( @cust_bill_pkg ) { - $cust_bill_pkg->setfield( 'invnum', $invnum ); + warn $cust_bill_pkg->invnum($invnum); $error = $cust_bill_pkg->insert; - #shouldn't happen, but how else tohandle this? if ( $error ) { $dbh->rollback if $oldAutoCommit; - return "$error for customer #". $self->custnum; + return "can't create invoice line item for customer #". $self->custnum. + ": $error"; } } @@ -906,6 +928,8 @@ a credit card (`CARD'), or just add any necessary (pseudo-)payment (`COMP'). If there is an error, returns the error, otherwise returns false. +Options are passed as name-value pairs. + Currently available options are: invoice_time - Use this time when deciding when to print invoices and @@ -937,10 +961,10 @@ sub collect { local $FS::UID::AutoCommit = 0; my $dbh = dbh; - my $total_owed = $self->balance; - warn "collect: total owed $total_owed " if $Debug; - unless ( $total_owed > 0 ) { #redundant????? - $dbh->rollback if $oldAutoCommit; + my $balance = $self->balance; + warn "collect: balance $balance" if $Debug; + unless ( $balance > 0 ) { #redundant????? + $dbh->rollback if $oldAutoCommit; #hmm return ''; } @@ -949,18 +973,18 @@ sub collect { ) { #this has to be before next's - my $amount = sprintf( "%.2f", $total_owed < $cust_bill->owed - ? $total_owed + my $amount = sprintf( "%.2f", $balance < $cust_bill->owed + ? $balance : $cust_bill->owed ); - $total_owed = sprintf( "%.2f", $total_owed - $amount ); + $balance = sprintf( "%.2f", $balance - $amount ); next unless $cust_bill->owed > 0; - # ?????????? + # don't try to charge for the same invoice if it's already in a batch next if qsearchs( 'cust_pay_batch', { 'invnum' => $cust_bill->invnum } ); - warn "invnum ". $cust_bill->invnum. " (owed ". $cust_bill->owed. ", amount $amount, total_owed $total_owed)" if $Debug; + warn "invnum ". $cust_bill->invnum. " (owed ". $cust_bill->owed. ", amount $amount, balance $balance)" if $Debug; next unless $amount > 0; @@ -1115,6 +1139,8 @@ sub collect { } elsif ( $processor =~ /^Business::OnlinePayment::(.*)$/ ) { + my $bop_processor = $1; + my($payname, $payfirst, $paylast); if ( $self->payname ) { $payname = $self->payname; @@ -1130,7 +1156,8 @@ sub collect { $payname = "$payfirst $paylast"; } - my $transaction = new Business::OnlinePayment( $1, @bop_options ); + my $transaction = + new Business::OnlinePayment( $bop_processor, @bop_options ); $transaction->content( 'type' => 'CC', 'login' => $bop_login, @@ -1177,7 +1204,7 @@ sub collect { $transaction->result_code. ": ". $transaction->error_message; } else { $dbh->commit or die $dbh->errstr if $oldAutoCommit; - return '' + #return ''; } } else { @@ -1226,7 +1253,7 @@ sub collect { =item total_owed Returns the total owed for this customer on all invoices -(see L). +(see L). =cut @@ -1323,7 +1350,7 @@ sub apply_payments { if ( $cust_bill->owed >= $payment->unapplied ) { $amount = $payment->unapplied; } else { - $amount = $payment->owed; + $amount = $cust_bill->owed; } my $cust_bill_pay = new FS::cust_bill_pay ( { @@ -1343,7 +1370,8 @@ sub apply_payments { =item total_credited -Returns the total credits (see L) for this customer. +Returns the total outstanding credit (see L) for this +customer. See L. =cut @@ -1358,15 +1386,36 @@ sub total_credited { sprintf( "%.2f", $total_credit ); } +=item total_unapplied_payments + +Returns the total unapplied payments (see L) for this customer. +See L. + +=cut + +sub total_unapplied_payments { + my $self = shift; + my $total_unapplied = 0; + foreach my $cust_pay ( qsearch('cust_pay', { + 'custnum' => $self->custnum, + } ) ) { + $total_unapplied += $cust_pay->unapplied; + } + sprintf( "%.2f", $total_unapplied ); +} + =item balance -Returns the balance for this customer (total owed minus total credited). +Returns the balance for this customer (total_owed minus total_credited +minus total_unapplied_payments). =cut sub balance { my $self = shift; - sprintf( "%.2f", $self->total_owed - $self->total_credited ); + sprintf( "%.2f", + $self->total_owed - $self->total_credited - $self->total_unapplied_payments + ); } =item invoicing_list [ ARRAYREF ] @@ -1501,7 +1550,7 @@ sub rebuild_fuzzyfiles { =head1 VERSION -$Id: cust_main.pm,v 1.28 2001-09-02 04:25:55 ivan Exp $ +$Id: cust_main.pm,v 1.29 2001-09-03 22:07:38 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 70d1b7314..42ca0b0a5 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -3,7 +3,7 @@ package FS::cust_pay; use strict; use vars qw( @ISA ); use Business::CreditCard; -use FS::Record qw( dbh ); +use FS::Record qw( dbh qsearch qsearchs ); use FS::cust_bill; use FS::cust_bill_pay; use FS::cust_main; @@ -94,6 +94,21 @@ sub insert { return $error if $error; if ( $self->invnum ) { + my $cust_bill = qsearchs('cust_bill', { 'invnum' => $self->invnum } ) + or do { + $dbh->rollback if $oldAutoCommit; + return "Unknown cust_bill.invnum: ". $self->invnum; + }; + $self->custnum($cust_bill->custnum ); + } + + $error = $self->SUPER::insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error inserting $self: $error"; + } + + if ( $self->invnum ) { my $cust_bill_pay = new FS::cust_bill_pay { 'invnum' => $self->invnum, 'paynum' => $self->paynum, @@ -103,18 +118,8 @@ sub insert { $error = $cust_bill_pay->insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; - return $error; + return "error inserting $cust_bill_pay: $error"; } - warn $cust_bill_pay; - warn $cust_bill_pay->cust_bill; - warn $cust_bill_pay->cust_bill->custnum; - $self->custnum($cust_bill_pay->cust_bill->custnum); - } - - $error = $self->SUPER::insert; - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return $error; } $dbh->commit or die $dbh->errstr if $oldAutoCommit; @@ -276,7 +281,7 @@ sub unapplied { =head1 VERSION -$Id: cust_pay.pm,v 1.6 2001-09-02 05:38:13 ivan Exp $ +$Id: cust_pay.pm,v 1.7 2001-09-03 22:07:38 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 77151b80e..daec79fe8 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -58,7 +58,7 @@ The following fields are currently supported: Creates a new service. To add the refund to the database, see L<"insert">. Services are normally created by creating FS::svc_ objects (see -L, L, and L, among others). +L, L, and L, among others). =cut @@ -155,7 +155,7 @@ sub label { =head1 VERSION -$Id: cust_svc.pm,v 1.4 2001-09-02 04:51:11 ivan Exp $ +$Id: cust_svc.pm,v 1.5 2001-09-03 22:07:38 ivan Exp $ =head1 BUGS diff --git a/FS/bin/freeside-bill b/FS/bin/freeside-bill index 3462fa149..1dce9a19b 100755 --- a/FS/bin/freeside-bill +++ b/FS/bin/freeside-bill @@ -55,15 +55,19 @@ foreach $cust_main ( warn "Error billing, customer #" . $cust_main->getfield('custnum') . ":" . $error if $error; + if ($main::opt_p) { + $cust_main->apply_payments; + $error=$cust_main->apply_credits; + } + if ($main::opt_c) { $error=$cust_main->collect('invoice_time'=>$time, 'batch_card' => $main::opt_i ? 'no' : 'yes', ); - warn "Error collecting customer #" . $cust_main->getfield('custnum') . - ":" . $error if $error; - - #sleep 1; + warn "Error collecting from customer #" . $cust_main->gcustnum. ":$error" + if $error; + #sleep 1; } } @@ -89,7 +93,7 @@ freeside-bill - Command line (crontab, script) interface to customer billing. =head1 SYNOPSIS - freeside-bill [ -c [ -a ] [ -i ] ] [ -d 'date' ] user [ custnum custnum ... ] + freeside-bill [ -c [ -p ] [ -a ] [ -i ] ] [ -d 'date' ] user [ custnum custnum ... ] =head1 DESCRIPTION @@ -98,6 +102,9 @@ the bill and collect methods of a cust_main object. See L. -c: Turn on collecting (you probably want this). + -p: Apply unapplied payments and credits before collecting (you probably want + this too) + -a: Call collect even if there isn't a new invoice (probably a bad idea for daily use) @@ -114,7 +121,7 @@ customers. Otherwise, bills all customers. =head1 VERSION -$Id: freeside-bill,v 1.7 2001-08-21 09:34:13 ivan Exp $ +$Id: freeside-bill,v 1.8 2001-09-03 22:07:39 ivan Exp $ =head1 BUGS diff --git a/httemplate/docs/signup.html b/httemplate/docs/signup.html index f99b7ebb5..262b697bb 100644 --- a/httemplate/docs/signup.html +++ b/httemplate/docs/signup.html @@ -42,7 +42,7 @@ Optional:
  • $password
  • $email_name - first and last name - (an example file is included as fs_signup/ieak.template) + (an example file is included as fs_signup/ieak.template) See the IEAK documentation for more information.
  • If you create a /usr/local/freeside/cck.template file on the external machine, the variables defined will be sent to Netscape users with MIME type application/x-netscape-autoconfigure-dialer-v2. This file will be processed with Text::Template with the following variables available:
    • $ac - area code of selected POP diff --git a/httemplate/docs/upgrade8.html b/httemplate/docs/upgrade8.html index 6d5018816..518d76168 100644 --- a/httemplate/docs/upgrade8.html +++ b/httemplate/docs/upgrade8.html @@ -181,8 +181,34 @@ ALTER TABLE cust_main ADD COLUMN comments varchar NULL; '; @@ -320,28 +320,31 @@ print ""; print "
      PostgreSQLMySQL, others
      -ALTER TABLE cust_pay RENAME COLUMN invnum TO depreciated;
      -ALTER TABLE cust_refund RENAME COLUMN crednum TO depreciated;
      +CREATE TABLE cust_pay_temp (
      +  paynum int primary key,
      +  custnum int not null,
      +  paid decimal(10,2) not null,
      +  _date int null,
      +  payby char(4) not null,
      +  payinfo varchar(16) null,
      +  paybatch varchar(80) null
      +);
      +INSERT INTO cust_pay_temp SELECT * from cust_pay;
      +DROP TABLE cust_pay;
      +ALTER TABLE cust_pay_temp RENAME TO cust_pay;
      +CREATE UNIQUE INDEX cust_pay1 ON cust_pay paynum;
      +CREATE TABLE cust_refund_temp (
      +  refundnum int primary key,
      +  custnum int not null,
      +  _date int null,
      +  refund decimal(10,2) not null,
      +  otaker varchar(8) not null,
      +  reason varchar(80) not null,
      +  payby char(4) not null,
      +  payinfo varchar(16) null,
      +  paybatch varchar(80) null
      +);
      +INSERT INTO cust_refund_temp SELECT * from cust_refund;
      +DROP TABLE cust_refund;
      +ALTER TABLE cust_refund_temp RENAME TO cust_refund;
      +CREATE UNIQUE INDEX cust_refund1 ON cust_refund refundnum;
       
      diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi
      index a95636662..9b215389a 100755
      --- a/httemplate/edit/cust_credit.cgi
      +++ b/httemplate/edit/cust_credit.cgi
      @@ -1,5 +1,5 @@
       <%
      -#
      +#
       
       use strict;
       use vars qw( $cgi $query $custnum $otaker $p1 $crednum $_date $amount $reason );
      @@ -42,31 +42,29 @@ print qq!Error: !, $cgi->param('error'),
         if $cgi->param('error');
       print <
      -    
       END
       
       $crednum = "";
       print qq!Credit #!, $crednum ? $crednum : " (NEW)", qq!!;
       
      -print qq!\nCustomer #$custnum!;
      +print qq!
      Customer #$custnum!; print qq!!; -print qq!\nDate: !, time2str("%D",$_date), qq!!; +print qq!
      Date: !, time2str("%D",$_date), qq!!; -print qq!\nAmount \$!; +print qq!
      Amount \$!; print qq!!; #print qq! Also post refund!; print qq!!; -print qq!\nReason !; +print qq!
      Reason !; print <
      -
      + END print < +# use strict; -use vars qw( $cgi $query $custnum $invnum $otaker $p1 $crednum $_date $amount $reason $cust_credit ); +use vars qw( $cgi $query $custnum $invnum $otaker $p1 $crednum $amount $reason $cust_credit ); use Date::Format; use CGI; use CGI::Carp qw(fatalsToBrowser); +use Date::Format; use FS::UID qw(cgisuidsetup getotaker); use FS::CGI qw(header popurl); use FS::Record qw(qsearch fields); @@ -32,7 +33,6 @@ if ( $cgi->param('error') ) { #$refund = 'yes'; $invnum = ''; } -$_date = time; $otaker = getotaker; @@ -44,31 +44,65 @@ print qq!Error: !, $cgi->param('error'), if $cgi->param('error'); print < -
       END
       
       die unless $cust_credit = qsearchs('cust_credit', { 'crednum' => $crednum } );
       
      -print qq!Credit #!, $crednum, qq!!;
      +my $credited = $cust_credit->credited;
      +
      +print "Credit # $crednum".
      +      qq!!.
      +      '
      Date: '. time2str("%D", $cust_credit->_date). ''. + '
      Amount: $'. $cust_credit->amount. ''. + "
      Unapplied amount: \$$credited". + '
      Reason: '. $cust_credit->reason. '' + ; + +my @cust_bill = grep $_->owed != 0, + qsearch('cust_bill', { 'custnum' => $cust_credit->custnum } ); + +print < +function changed(what) { + cust_bill = what.options[what.selectedIndex].value; +END -print qq!\nInvoice # "; -print qq!\nDate: !, time2str("%D",$_date), qq!!; +print < +END -print qq!\nAmount \$!; +print qq!
      Invoice #"; -#print qq! Also post refund!; +print qq!
      Amount \$!; print <
      -
      + END print < +# use strict; -use vars qw( $cgi $invnum $p1 $_date $payby $payinfo $paid ); +use vars qw( $cgi $link $linknum $p1 $_date $payby $payinfo $paid ); use Date::Format; use CGI; use CGI::Carp qw(fatalsToBrowser); @@ -13,17 +13,27 @@ $cgi = new CGI; cgisuidsetup($cgi); if ( $cgi->param('error') ) { - $invnum = $cgi->param('invnum'); + $link = $cgi->param('link'); + $linknum = $cgi->param('linknum'); $paid = $cgi->param('paid'); $payby = $cgi->param('payby'); $payinfo = $cgi->param('payinfo'); -} else { - my ($query) = $cgi->keywords; +} elsif ($cgi->keywords) { + my($query) = $cgi->keywords; $query =~ /^(\d+)$/; - $invnum = $1; + $link = 'invnum'; + $linknum = $1; $paid = ''; - $payby = "BILL"; + $payby = 'BILL'; $payinfo = ""; +} elsif ( $cgi->param('custnum') =~ /^(\d+)$/ ) { + $link = 'custnum'; + $linknum = $1; + $paid = ''; + $payby = 'BILL'; + $payinfo = ''; +} else { + die "illegal query ". $cgi->keywords; } $_date = time; @@ -36,10 +46,15 @@ print qq!Error: !, $cgi->param('error'), print < -
      +    
      +    
       END
       
      -print qq!Invoice #$invnum!;
      +if ( $link eq 'invnum' ) {
      +  print "Invoice #$linknum";
      +} elsif ( $link eq 'custnum' ) {
      +  print "Customer #$linknum";
      +}
       
       print qq!
      Date: !, time2str("%D",$_date), qq!!; diff --git a/httemplate/edit/process/cust_pay.cgi b/httemplate/edit/process/cust_pay.cgi index fcdc233b9..9be96505d 100755 --- a/httemplate/edit/process/cust_pay.cgi +++ b/httemplate/edit/process/cust_pay.cgi @@ -1,8 +1,8 @@ <% -# +# use strict; -use vars qw( $cgi $invnum $new $error ); +use vars qw( $cgi $link $linknum $new $error ); use CGI; use CGI::Carp qw(fatalsToBrowser); use FS::UID qw(cgisuidsetup); @@ -13,24 +13,32 @@ use FS::cust_pay; $cgi = new CGI; &cgisuidsetup($cgi); -$cgi->param('invnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; -$invnum = $1; +$cgi->param('linknum') =~ /^(\d+)$/ + or die "Illegal linknum: ". $cgi->param('linknum'); +$linknum = $1; + +$cgi->param('link') =~ /^(custnum|invnum)$/ + or die "Illegal link: ". $cgi->param('link'); +$link = $1; $new = new FS::cust_pay ( { + $link => $linknum, map { $_, scalar($cgi->param($_)); - #} qw(invnum paid _date payby payinfo paybatch) - } fields('cust_pay') + } qw(paid _date payby payinfo paybatch) + #} fields('cust_pay') } ); -$error=$new->insert; +$error = $new->insert; if ($error) { $cgi->param('error', $error); print $cgi->redirect(popurl(2). 'cust_pay.cgi?'. $cgi->query_string ); exit; -} else { - print $cgi->redirect(popurl(3). "view/cust_bill.cgi?$invnum"); +} elsif ( $link eq 'invnum' ) { + print $cgi->redirect(popurl(3). "view/cust_bill.cgi?$linknum"); +} elsif ( $link eq 'custnum' ) { + print $cgi->redirect(popurl(3). "view/cust_main.cgi?$linknum"); } %> diff --git a/httemplate/misc/bill.cgi b/httemplate/misc/bill.cgi index cc7938308..43c7c576d 100755 --- a/httemplate/misc/bill.cgi +++ b/httemplate/misc/bill.cgi @@ -1,5 +1,5 @@ <% -# +# use strict; use vars qw( $cgi $query $custnum $cust_main $error ); @@ -25,6 +25,9 @@ $error = $cust_main->bill( ); &eidiot($error) if $error; +$cust_main->apply_payments; +$cust_main->apply_credits; + $error = $cust_main->collect( # 'invoice-time'=>$time, # 'batch_card'=> 'yes', diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi index 12fe8578a..1e024f377 100755 --- a/httemplate/view/cust_bill.cgi +++ b/httemplate/view/cust_bill.cgi @@ -1,5 +1,5 @@ <% -# +# use strict; use vars qw ( $cgi $query $invnum $cust_bill $custnum $printed $p ); @@ -29,9 +29,13 @@ $p = popurl(2); print $cgi->header( '-expires' => 'now' ), header('Invoice View', menubar( "Main Menu" => $p, "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum", -)), <Enter payments (check/cash) against this invoice -
      Reprint this invoice +)); + +print qq!Enter payments (check/cash) against this invoice | ! + if $cust_bill->owed > 0; + +print <Reprint this invoice

      (Printed $printed times)
       END
      diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi
      index 6ece5c2be..a32abc0e1 100755
      --- a/httemplate/view/cust_main.cgi
      +++ b/httemplate/view/cust_main.cgi
      @@ -1,5 +1,5 @@
       <%
      -#
      +#
       
       use strict;
       use vars qw ( $cgi $query $custnum $cust_main $hashref $agent $referral 
      @@ -192,7 +192,7 @@ print '
      '; @invoicing_list = $cust_main->invoicing_list; print "Billing information (", - qq!!, "Bill now)", + qq!!, "Bill now)", &ntable("#cccccc"), "
      ", &ntable("#cccccc",2), '
      Tax exempt', $cust_main->tax ? 'yes' : 'no', @@ -269,9 +269,9 @@ print qq!!, &table(), "\n", #get package info if ( $conf->exists('hidecancelledpackages') ) { - @packages = $cust_main->ncancelled_pkgs; + @packages = sort { $a->pkgnum <=> $b->pkgnum } ($cust_main->ncancelled_pkgs); } else { - @packages = $cust_main->all_pkgs; + @packages = sort { $a->pkgnum <=> $b->pkgnum } ($cust_main->all_pkgs); } $n1 = '
      "; #formatting -print qq!

      Payment History!, - qq!!, - qq! ( Click on invoice to view invoice/enter payment. | !, - qq!!, - qq!Post credit / refund )!; +print qq!

      Payment History!. + qq! ( !. + qq!!. + qq!Post payment | !. + qq!!. + qq!Post credit )!; #get payment history # # major problem: this whole thing is way too sloppy. # minor problem: the description lines need better formatting. -# SHOULD SHOW UNAPPLIED PAYMENTS (now show unapplied credits) - @history = (); #needed for mod_perl :) @bills = qsearch('cust_bill',{'custnum'=>$custnum}); foreach $bill (@bills) { my($bref)=$bill->hashref; + my $bpre = ( $bill->owed > 0 ) + ? ' Open ' + : ''; + my $bpost = ( $bill->owed > 0 ) ? '' : ''; push @history, $bref->{_date} . qq!\tInvoice #! . $bref->{invnum} . - qq! (Balance \$! . $bill->owed . qq!)\t! . + $bref->{invnum} . qq!">${bpre}Invoice #! . $bref->{invnum} . + qq! (Balance \$! . $bill->owed . qq!)$bpost\t! . $bref->{charged} . qq!\t\t\t!; my(@cust_bill_pay)=qsearch('cust_bill_pay',{'invnum'=> $bref->{invnum} } ); @@ -356,6 +359,7 @@ foreach $bill (@bills) { $payment->payinfo, $cust_bill_pay->amount, ); + $payinfo = substr($payinfo,0,4). 'x'x(length($payinfo)-4) if $payby eq 'CARD'; push @history, "$date\tPayment, Invoice #$invnum ($payby $payinfo)\t\t$paid\t\t"; } @@ -364,33 +368,34 @@ foreach $bill (@bills) { qsearch('cust_credit_bill', { 'invnum'=> $bref->{invnum} } ); foreach my $cust_credit_bill (@cust_credit_bill) { my $cust_credit = $cust_credit_bill->cust_credit; - my($date, $invnum, $crednum, $amount, $reason ) = ( + my($date, $invnum, $crednum, $amount, $reason, $app_date ) = ( $cust_credit->_date, $cust_credit_bill->invnum, $cust_credit_bill->crednum, $cust_credit_bill->amount, $cust_credit->reason, + time2str("%D", $cust_credit_bill->_date), ); push @history, - "$date\tCredit #$crednum, Invoice #$invnum $reason\t\t\t$amount\t"; + "$date\tCredit #$crednum: $reason
      ". + "(applied to invoice #$invnum on $app_date)\t\t\t$amount\t"; } } -@credits = grep $_->credited, qsearch('cust_credit',{'custnum'=>$custnum}); +@credits = grep { $_->credited > 0 } + qsearch('cust_credit',{'custnum'=>$custnum}); foreach $credit (@credits) { my($cref)=$credit->hashref; push @history, $cref->{_date} . "\t" . qq!!. - 'Unapplied credit #' . - $cref->{crednum} . ", (Balance \$" . - $credit->credited . ") ". - $cref->{reason} . "\t\t\t" . $cref->{amount} . "\t"; + 'Unapplied credit #' . + $cref->{crednum} . ": ". + $cref->{reason} . "\t\t\t" . $credit->credited . "\t"; } my(@refunds)=qsearch('cust_refund',{'custnum'=> $custnum } ); -my($refund); -foreach $refund (@refunds) { +foreach my $refund (@refunds) { my($rref)=$refund->hashref; my($refundnum) = ( $refund->refundnum, @@ -403,6 +408,16 @@ foreach $refund (@refunds) { $rref->{refund}; } +my @unapplied_payments = + grep { $_->unapplied > 0 } qsearch('cust_pay', { 'custnum' => $custnum } ); +foreach my $payment (@unapplied_payments) { + push @history, + $payment->_date. "\t". + ''. + 'Unapplied payment #' . + $payment->paynum . "". + "\t\t" . $payment->unapplied . "\t\t"; +} #formatting print &table(), <