freeside/httemplate/view/cust_main payment_history.html,NONE,1.1 packages.html,NONE,1.1 order_pkg.html,NONE,1.1 quick-charge.html,NONE,1.1

ivan ivan at pouncequick.420.am
Fri Dec 10 23:51:03 PST 2004


Update of /home/cvs/cvsroot/freeside/httemplate/view/cust_main
In directory pouncequick:/tmp/cvs-serv2268/cust_main

Added Files:
	payment_history.html packages.html order_pkg.html 
	quick-charge.html 
Log Message:
voiding of echeck payments instead of refunds

--- NEW FILE: quick-charge.html ---
<%
  my( $cust_main ) = @_;
  my $conf = new FS::Conf;
%>

<FORM ACTION="${p}edit/process/quick-charge.cgi" METHOD="POST">
<INPUT TYPE="hidden" NAME="custnum" VALUE="<%= $cust_main->custnum %>">
Description:<INPUT TYPE="text" NAME="pkg">
&nbsp;Amount:<INPUT TYPE="text" NAME="amount" SIZE=6>
&nbsp;<% 
  
  #false laziness w/ edit/part_pkg.cgi
  if ( $conf->exists('enable_taxclasses') ) {
    print '<SELECT NAME="taxclass">';
    my $sth = dbh->prepare('SELECT DISTINCT taxclass FROM cust_main_county')
      or die dbh->errstr;
    $sth->execute or die $sth->errstr;
    foreach my $taxclass ( map $_->[0], @{$sth->fetchall_arrayref} ) {
      print qq!<OPTION VALUE="$taxclass"!;
      #print ' SELECTED' if $taxclass eq $hashref->{taxclass};
      print qq!>$taxclass</OPTION>!;
    }
    print '</SELECT>';
  } else {
    print '<INPUT TYPE="hidden" NAME="taxclass" VALUE="">';
  }

%>
  
<INPUT TYPE="submit" VALUE="One-time charge">
</FORM>


--- NEW FILE: packages.html ---
<%
  my( $cust_main ) = @_;
  my $conf = new FS::Conf;

  my $packages = get_packages($cust_main, $conf);
%>

<A NAME="cust_pkg">Packages</A>
( <A HREF="<%= $p %>edit/cust_pkg.cgi?<%= $cust_main->custnum %>">Bulk order and cancel packages</A> (preserves services) )

<% if ( @$packages ) { %>

<TABLE CLASS="package" BORDER=1 CELLSPACING=0 CELLPADDING=2 BORDERCOLOR="#999999">
<TR>
  <TH>Package</TH>
  <TH>Status</TH>
  <TH COLSPAN=2>Services</TH>
</TR>

<%
foreach my $pkg (sort pkgsort_pkgnum_cancel @$packages) {
  my $rowspan = 0;

  if ($pkg->{cancel}) {
    $rowspan = 0;
  } else {
    foreach my $svcpart (@{$pkg->{svcparts}}) {
      $rowspan += $svcpart->{count};
      $rowspan++ if ($svcpart->{count} < $svcpart->{quantity});
    }
  } 
%>

<!--pkgnum: <%=$pkg->{pkgnum}%>-->
<TR>
  <TD ROWSPAN=<%=$rowspan%>>
    <A NAME="cust_pkg<%=$pkg->{pkgnum}%>"><%=$pkg->{pkgnum}%></A>:
    <%=$pkg->{pkg}%> - <%=$pkg->{comment}%><BR>
<% unless ($pkg->{cancel}) { %>
    (&nbsp;<%=pkg_change_link($pkg)%>&nbsp;)
    (&nbsp;<%=pkg_dates_link($pkg)%>&nbsp;|&nbsp;<%=pkg_customize_link($pkg,$cust_main->custnum)%>&nbsp;)
<% } %>
  </TD>
<%
  #foreach (qw(setup last_bill next_bill susp expire cancel)) {
  #  print qq!  <TD ROWSPAN=$rowspan>! . pkg_datestr($pkg,$_,$conf) . qq!</TD>\n!;
  #}
  print "<TD ROWSPAN=$rowspan>". &itable('');

  sub myfreq {
    my $part_pkg = shift;
    my $freq = $part_pkg->freq_pretty;
    $freq =~ s/ /&nbsp;/g;
    $freq;
  }

  if ( $pkg->{cancel} ) { #status: cancelled

    print '<TR><TD><FONT COLOR="#ff0000"><B>Cancelled&nbsp;</B></FONT></TD>'.
          '<TD>'. pkg_datestr($pkg,'cancel',$conf). '</TD></TR>';
    unless ( $pkg->{setup} ) {
      print '<TR><TD COLSPAN=2>Never billed</TD></TR>';
    } else {
      print "<TR><TD>Setup&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'setup',$conf). '</TD></TR>';
      print "<TR><TD>Last&nbsp;bill&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'last_bill',$conf). '</TD></TR>'
        if $pkg->{'last_bill'};
      print "<TR><TD>Suspended&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'susp',$conf). '</TD></TR>'
        if $pkg->{'susp'};
    }

  } else {

    if ( $pkg->{susp} ) { #status: suspended
      print '<TR><TD><FONT COLOR="#FF9900"><B>Suspended</B>&nbsp;</FONT></TD>'.
            '<TD>'. pkg_datestr($pkg,'susp',$conf). '</TD></TR>';
      unless ( $pkg->{setup} ) {
        print '<TR><TD COLSPAN=2>Never billed</TD></TR>';
      } else {
        print "<TR><TD>Setup&nbsp;</TD><TD>". 
              pkg_datestr($pkg, 'setup',$conf). '</TD></TR>';
      }
      print "<TR><TD>Last&nbsp;bill&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'last_bill',$conf). '</TD></TR>'
        if $pkg->{'last_bill'};
      # next bill ??
      print "<TR><TD>Expires&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'expire',$conf). '</TD></TR>'
        if $pkg->{'expire'};
      print '<TR><TD COLSPAN=2>(&nbsp;'. pkg_unsuspend_link($pkg).
            '&nbsp;|&nbsp;'. pkg_cancel_link($pkg). '&nbsp;)</TD></TR>';

    } else { #status: active

      unless ( $pkg->{setup} ) { #not setup

        print '<TR><TD COLSPAN=2>Not&nbsp;yet&nbsp;billed&nbsp;(';
        unless ( $pkg->{freq} ) {
          print 'one-time&nbsp;charge)</TD></TR>';
          print '<TR><TD COLSPAN=2>(&nbsp;'. pkg_cancel_link($pkg).
                '&nbsp;)</TD</TR>';
        } else {
          print 'billed&nbsp;'. myfreq($pkg->{part_pkg}). ')</TD></TR>';
        }

      } else { #setup

        unless ( $pkg->{freq} ) {
          print "<TR><TD COLSPAN=2>One-time&nbsp;charge</TD></TR>".
                '<TR><TD>Billed&nbsp;</TD><TD>'.
                pkg_datestr($pkg,'setup',$conf). '</TD></TR>';
        } else {
          print '<TR><TD COLSPAN=2><FONT COLOR="#00CC00"><B>Active</B></FONT>'.
                ',&nbsp;billed&nbsp;'. myfreq($pkg->{part_pkg}). '</TD></TR>'.
                '<TR><TD>Setup&nbsp;</TD><TD>'.
                pkg_datestr($pkg, 'setup',$conf). '</TD></TR>';
        }

      }

      print "<TR><TD>Last&nbsp;bill&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'last_bill',$conf). '</TD></TR>'
        if $pkg->{'last_bill'};
      print "<TR><TD>Next&nbsp;bill&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'next_bill',$conf). '</TD></TR>'
        if $pkg->{'next_bill'};
      print "<TR><TD>Expires&nbsp;</TD><TD>".
            pkg_datestr($pkg, 'expire',$conf). '</TD></TR>'
        if $pkg->{'expire'};
      if ( $pkg->{freq} ) {
        print '<TR><TD COLSPAN=2>(&nbsp;'. pkg_suspend_link($pkg).
              '&nbsp;|&nbsp;'. pkg_cancel_link($pkg). '&nbsp;)</TD></TR>';
      }

    }

  }

  print "</TABLE></TD>\n";

  if ($rowspan == 0) { print qq!</TR>\n!; next; }

  my $cnt = 0;
  foreach my $svcpart (sort {$a->{svcpart} <=> $b->{svcpart}} @{$pkg->{svcparts}}) {
    foreach my $service (@{$svcpart->{services}}) {
      print '<TR>' if ($cnt > 0);
%>
  <TD><%=svc_link($svcpart,$service)%></TD>
  <TD><%=svc_label_link($svcpart,$service)%><BR>(&nbsp;<%=svc_unprovision_link($service)%>&nbsp;)</TD>
</TR>
<%
      $cnt++;
    }
    if ($svcpart->{count} < $svcpart->{quantity}) {
      print qq!<TR>\n! if ($cnt > 0);
      print qq!  <TD COLSPAN=2>!.svc_provision_link($pkg, $svcpart, $conf).qq!</TD>\n</TR>\n!;
    }
  }
}
print '</TABLE>';
}

#end display packages
%>

<%
#subroutines

sub get_packages {
  my $cust_main = shift or return undef;
  my $conf = shift;
  
  my @packages = ();
  
  foreach my $cust_pkg (
    $conf->exists('hidecancelledpackages')
      ? $cust_main->ncancelled_pkgs
      : $cust_main->all_pkgs
  ) { 
  
    my $part_pkg = $cust_pkg->part_pkg;

    my %pkg = ();

    #to get back to the original object... should use it in the first place!!
    $pkg{cust_pkg} = $cust_pkg;
    $pkg{part_pkg} = $part_pkg;

    $pkg{pkgnum} = $cust_pkg->pkgnum;
    $pkg{pkg} = $part_pkg->pkg;
    $pkg{pkgpart} = $part_pkg->pkgpart;
    $pkg{comment} = $part_pkg->getfield('comment');
    $pkg{freq} = $part_pkg->freq;
    $pkg{setup} = $cust_pkg->getfield('setup');
    $pkg{last_bill} = $cust_pkg->getfield('last_bill');
    $pkg{next_bill} = $cust_pkg->getfield('bill');
    $pkg{susp} = $cust_pkg->getfield('susp');
    $pkg{expire} = $cust_pkg->getfield('expire');
    $pkg{cancel} = $cust_pkg->getfield('cancel');

  
    my %svcparts = map {
      $_->svcpart => {
                       $_->part_svc->hash,
                       'quantity' => $_->quantity,
                       'count'    => $cust_pkg->num_cust_svc($_->svcpart),
                       #'services' => [],
                     };
    } $part_pkg->pkg_svc;

    foreach my $cust_svc ( $cust_pkg->cust_svc ) {
      #warn "svcnum ". $cust_svc->svcnum. " / svcpart ". $cust_svc->svcpart. "\n";
      my $svc = {
        'svcnum' => $cust_svc->svcnum,
        'label'  => ($cust_svc->label)[1],
      };

      #false laziness with above, to catch extraneous services.  whole
      #damn thing should be OO...
      my $svcpart = ( $svcparts{$cust_svc->svcpart} ||= {
        $cust_svc->part_svc->hash,
        'quantity' => 0,
        'count'    => $cust_pkg->num_cust_svc($cust_svc->svcpart),
        #'services' => [],
      } );

      push @{$svcpart->{services}}, $svc;

    }

    $pkg{svcparts} = [ values %svcparts ];

    push @packages, \%pkg;
  
  }
  
  return \@packages;

}

sub svc_link {

  my ($svcpart, $svc) = (shift,shift) or return '';
  return qq!<A HREF="${p}view/$svcpart->{svcdb}.cgi?$svc->{svcnum}">$svcpart->{svc}</A>!;

}

sub svc_label_link {

  my ($svcpart, $svc) = (shift,shift) or return '';
  return qq!<A HREF="${p}view/$svcpart->{svcdb}.cgi?$svc->{svcnum}">$svc->{label}</A>!;

}

sub svc_provision_link {
  my ($pkg, $svcpart, $conf) = @_;
  ( my $svc_nbsp = $svcpart->{svc} ) =~ s/\s+/&nbsp;/g;
  my $num_left = $svcpart->{quantity} - $svcpart->{count};
  my $pkgnum_svcpart = "pkgnum$pkg->{pkgnum}-svcpart$svcpart->{svcpart}";

  my $url;
  if ( $svcpart->{svcdb} eq 'svc_external'
       && $conf->exists('svc_external-skip_manual')
  ) {
    $url = "${p}edit/process/$svcpart->{svcdb}.cgi?".
           "pkgnum=$pkg->{pkgnum}&".
           "svcpart=$svcpart->{svcpart}";
  } else {
    $url = "${p}edit/$svcpart->{svcdb}.cgi?$pkgnum_svcpart";
  }

  my $link = qq!<A CLASS="provision" HREF="$url">!.
             "Provision&nbsp;$svc_nbsp&nbsp;($num_left)</A>";
  if ( $conf->exists('legacy_link') ) {
    $link .= '<BR>'.
             qq!<A CLASS="provision" HREF="${p}misc/link.cgi?!.
             qq!$pkgnum_svcpart">!.
            "Link&nbsp;to&nbsp;legacy&nbsp;$svc_nbsp&nbsp;($num_left)</A>";
  }
  $link;
}

sub svc_unprovision_link {
  my $svc = shift or return '';
  qq!<A HREF="javascript:areyousure('${p}misc/unprovision.cgi?$svc->{svcnum}',!.
  qq!'Permanently unprovision and delete this service?')">Unprovision</A>!;
}

# This should be generalized to use config options to determine order.
sub pkgsort_pkgnum_cancel {
  if ($a->{cancel} and $b->{cancel}) {
    return ($a->{pkgnum} <=> $b->{pkgnum});
  } elsif ($a->{cancel} or $b->{cancel}) {
    return (-1) if ($b->{cancel});
    return (1) if ($a->{cancel});
    return (0);
  } else {
    return($a->{pkgnum} <=> $b->{pkgnum});
  }
}

sub pkg_datestr {
  my($pkg, $field, $conf) = @_ or return '';
  return '&nbsp;' unless $pkg->{$field};
  my $format = $conf->exists('pkg_showtimes')
               ? '<B>%D</B>&nbsp;<FONT SIZE=-3>%l:%M:%S%P&nbsp;%z</FONT>'
               : '<B>%b&nbsp;%o,&nbsp;%Y</B>';
  ( my $strip = time2str($format, $pkg->{$field}) ) =~ s/ (\d)/$1/g;
  $strip;
}

sub pkg_change_link {
  my $pkg = shift or return '';
  return qq!<a href="${p}misc/change_pkg.cgi?$pkg->{pkgnum}">!.
         qq!Change&nbsp;package</a>!;
}

sub pkg_suspend_link {
  my $pkg = shift or return '';
  return qq!<a href="${p}misc/susp_pkg.cgi?$pkg->{pkgnum}">Suspend</a>!;
}

sub pkg_unsuspend_link {
  my $pkg = shift or return '';
  return qq!<a href="${p}misc/unsusp_pkg.cgi?$pkg->{pkgnum}">Unsuspend</a>!;
}

sub pkg_cancel_link {
  my $pkg = shift or return '';
  qq!<A HREF="javascript:areyousure('${p}misc/cancel_pkg.cgi?$pkg->{pkgnum}', !.
  qq!'Permanently delete included services and cancel this package?')">!.
  qq!Cancel now</A> | !.
  qq!<A HREF="${p}misc/expire_pkg.cgi?$pkg->{pkgnum}">Cancel later</A>!;
}

sub pkg_dates_link {
  my $pkg = shift or return '';
  qq!<A HREF="${p}edit/REAL_cust_pkg.cgi?$pkg->{pkgnum}">Edit&nbsp;dates</A>!;
}

sub pkg_customize_link {
  my $pkg = shift or return '';
  my $custnum = shift;
  qq!<A HREF="${p}edit/part_pkg.cgi?keywords=$custnum;clone=$pkg->{pkgpart};!.
  qq!pkgnum=$pkg->{pkgnum}">Customize</A>!;
}

%>

--- NEW FILE: payment_history.html ---
<%
  my( $cust_main ) = @_;
  my $conf = new FS::Conf;
  my $custnum = $cust_main->custnum;
%>

<BR><BR><A NAME="history"><FONT SIZE="+2">Payment History</FONT></A><BR>
<A HREF="<%= $p %>edit/cust_pay.cgi?custnum=<%= $custnum %>">Post cash/check payment</A>
| <A HREF="<%= $p %>misc/payment.cgi?payby=CARD;custnum=<%= $custnum %>">Process credit card payment</A>
| <A HREF="<%= $p %>misc/payment.cgi?payby=CHEK;custnum=<%= $custnum %>">Process electronic check (ACH) payment</A>
<BR><A HREF="<%= $p %>edit/cust_credit.cgi?<%= $custnum %>">Post credit</A>
<BR>

<%
#get payment history
my @history = ();

#invoices
foreach my $cust_bill ($cust_main->cust_bill) {
  my $pre = ( $cust_bill->owed > 0 )
              ? '<B><FONT SIZE="+1" COLOR="#FF0000">Open '
              : '';
  my $post = ( $cust_bill->owed > 0 ) ? '</FONT></B>' : '';
  my $invnum = $cust_bill->invnum;
  push @history, {
    'date'   => $cust_bill->_date,
    'desc'   => qq!<A HREF="${p}view/cust_bill.cgi?$invnum">!. $pre.
                "Invoice #$invnum (Balance \$". $cust_bill->owed. ')'.
                $post. '</A>',
    'charge' => $cust_bill->charged,
  };
}

#payments (some false laziness w/credits)
foreach my $cust_pay ($cust_main->cust_pay) {

  my $payby = $cust_pay->payby;

  my $payinfo;
  if ( $payby eq 'CARD' ) {
    $payinfo = $cust_pay->payinfo_masked;
  } elsif ( $payby eq 'CHEK' && $cust_pay->payinfo =~ /^(\d+)\@(\d+)$/ ) {
    $payinfo = "ABA $2, Acct# $1";
  } else {
    $payinfo = $cust_pay->payinfo;
  }
  my @cust_bill_pay = $cust_pay->cust_bill_pay;
  my @cust_pay_refund = $cust_pay->cust_pay_refund;

  my $target = "$payby$payinfo";
  $payby =~ s/^BILL$/Check #/ if $payinfo;
  $payby =~ s/^CHEK$/Electronic check /;
  $payby =~ s/^BILL$//;
  $payby =~ s/^(CARD|COMP)$/$1 /;
  my $info = $payby ? " ($payby$payinfo)" : '';

  my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
  if (    scalar(@cust_bill_pay)   == 0
       && scalar(@cust_pay_refund) == 0 ) {
    #completely unapplied
    $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
    $post = '</FONT></B>';
    $apply = qq! (<A HREF="${p}edit/cust_bill_pay.cgi?!.
             $cust_pay->paynum. '">apply</A>)';
  } elsif (    scalar(@cust_bill_pay)   == 1
            && scalar(@cust_pay_refund) == 0
            && $cust_pay->unapplied == 0     ) {
    #applied to one invoice, the usual situation
    $desc = ' applied to Invoice #'. $cust_bill_pay[0]->invnum;
  } 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);
  } else {
    #complicated
    $desc = '<BR>';
    foreach my $app ( sort { $a->_date <=> $b->_date }
                           ( @cust_bill_pay, @cust_pay_refund ) ) {
      if ( $app->isa('FS::cust_bill_pay') ) {
        $desc .= '&nbsp;&nbsp;'.
                 '$'. $app->amount.
                 ' applied to Invoice #'. $app->invnum.
                 '<BR>';
                 #' on '. time2str("%D", $cust_bill_pay->_date).
      } elsif ( $app->isa('FS::cust_pay_refund') ) {
        $desc .= '&nbsp;&nbsp;'.
                 '$'. $app->amount.
                 ' refunded on'. time2str("%D", $app->_date).
                 '<BR>';
      } else {
        die "$app is not a FS::cust_bill_pay or FS::cust_pay_refund";
      }
    }
    if ( $cust_pay->unapplied > 0 ) {
      $desc .= '&nbsp;&nbsp;'.
               '<B><FONT COLOR="#FF0000">$'.
               $cust_pay->unapplied. ' unapplied</FONT></B>'.
               qq! (<A HREF="${p}edit/cust_bill_pay.cgi?!.
               $cust_pay->paynum. '">apply</A>)'.
               '<BR>';
    }
  }

  my $refund = '';
  my $refund_days = $conf->config('card_refund-days') || 120;
  if (    $cust_pay->closed !~ /^Y/i
       && $cust_pay->payby =~ /^(CARD|CHEK)$/
       && time-$cust_pay->_date < $refund_days*86400
       && $cust_pay->unrefunded > 0
  ) {
    $refund = qq! (<A HREF="${p}edit/cust_refund.cgi?payby=$1;!.
              qq!paynum=!. $cust_pay->paynum. '"'.
              qq! TITLE="Send a refund for this payment to the payment gateway"!.
              qq!>refund</A>)!;
  }

  my $void = '';
  if (    $cust_pay->closed !~ /^Y/i
       && $cust_pay->payby ne 'CARD'
       && ( $cust_pay->payby ne 'CHEK' || $conf->exists('echeck-void') ) 
     ) {
    $void = qq! (<A HREF="javascript:areyousure('!.
            qq!${p}misc/void-cust_pay.cgi?!. $cust_pay->paynum.
            qq!', 'Are you sure you want to void this payment?')"!.
            qq! TITLE="Void this payment from the database!.
              ( $cust_pay->payby eq 'CHEK'
                ? ' (do not send anything to the payment gateway)'
                : '' 
              ). '"'.
            qq!>void</A>)!;
  }

  my $delete = '';
  if ( $cust_pay->closed !~ /^Y/i && $conf->exists('deletepayments') ) {
    $delete = qq! (<A HREF="javascript:areyousure('!.
              qq!${p}misc/delete-cust_pay.cgi?!. $cust_pay->paynum.
              qq!', 'Are you sure you want to delete this payment?')"!.
              qq! TITLE="Delete this payment from the database completely - not recommended"!.
              qq!>delete</A>)!;
  }

  my $unapply = '';
  if (    $cust_pay->closed !~ /^Y/i
       && $conf->exists('unapplypayments')
       && scalar(@cust_bill_pay)           ) {
    $unapply = qq! (<A HREF="javascript:areyousure('!.
               qq!${p}misc/unapply-cust_pay.cgi?!. $cust_pay->paynum.
               qq!', 'Are you sure you want to unapply this payment?')"!.
               qq! TITLE="Keep this payment, but dissociate it from the invoices it is currently applied against"!.
               qq!>unapply</A>)!;
  }

  push @history, {
    'date'    => $cust_pay->_date,
    'desc'    => $pre. "Payment$post$info$desc".
                 "$apply$refund$void$delete$unapply",
    'payment' => $cust_pay->paid,
    'target'  => $target,
  };
}

#voided payments
foreach my $cust_pay_void ($cust_main->cust_pay_void) {

  my $payby = $cust_pay_void->payby;
  my $payinfo = $payby eq 'CARD'
                  ? $cust_pay_void->payinfo_masked
                  : $cust_pay_void->payinfo;

  $payby =~ s/^BILL$/Check #/ if $payinfo;
  $payby =~ s/^CHEK$/Electronic check /;
  $payby =~ s/^BILL$//;
  $payby =~ s/^(CARD|COMP)$/$1 /;
  my $info = $payby ? " ($payby$payinfo)" : '';

  push @history, {
    'date'   => $cust_pay_void->_date,
    'desc'   => "<DEL>Payment $info</DEL> <I>voided ".
                time2str("%D", $cust_pay_void->void_date).
                " by ". $cust_pay_void->otaker. '</i>',
    'void_payment' => $cust_pay_void->paid,
  };

}

#credits (some false laziness w/payments)
foreach my $cust_credit ($cust_main->cust_credit) {

  my @cust_credit_bill = $cust_credit->cust_credit_bill;
  my @cust_credit_refund = $cust_credit->cust_credit_refund;

  my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
  if (    scalar(@cust_credit_bill)   == 0
       && scalar(@cust_credit_refund) == 0 ) {
    #completely unapplied
    $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
    $post = '</FONT></B>';
    $apply = qq! (<A HREF="${p}edit/cust_credit_bill.cgi?!.
             $cust_credit->crednum. '">apply</A>)';
  } elsif (    scalar(@cust_credit_bill)   == 1
            && scalar(@cust_credit_refund) == 0
            && $cust_credit->credited == 0      ) {
    #applied to one invoice, the usual situation
    $desc = ' applied to Invoice #'. $cust_credit_bill[0]->invnum;
  } 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);
  } else {
    #complicated
    $desc = '<BR>';
    foreach my $app ( sort { $a->_date <=> $b->_date }
                           ( @cust_credit_bill, @cust_credit_refund ) ) {
      if ( $app->isa('FS::cust_credit_bill') ) {
        $desc .= '&nbsp;&nbsp;'.
                 '$'. $app->amount.
                 ' applied to Invoice #'. $app->invnum.
                 '<BR>';
                 #' on '. time2str("%D", $app->_date).
      } elsif ( $app->isa('FS::cust_credit_refund') ) {
        $desc .= '&nbsp;&nbsp;'.
                 '$'. $app->amount.
                 ' refunded on'. time2str("%D", $app->_date).
                 '<BR>';
      } else {
        die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund";
      }
    }
    if ( $cust_credit->credited > 0 ) {
      $desc .= '&nbsp;&nbsp;<B><FONT COLOR="#FF0000">$'.
               $cust_credit->credited. ' unapplied</FONT></B>'.
               qq! (<A HREF="${p}edit/cust_credit_bill.cgi?!.
               $cust_credit->crednum. '">apply</A>)'.
               '<BR>';
    }
  }
#
  my $delete = '';
  if ( $cust_credit->closed !~ /^Y/i && $conf->exists('deletecredits') ) {
    $delete = qq! (<A HREF="javascript:areyousure('!.
              qq!${p}misc/delete-cust_credit.cgi?!. $cust_credit->crednum.
              qq!', 'Are you sure you want to delete this credit?')">!.
              qq!delete</A>)!;
  }
  
  my $unapply = '';
  if (    $cust_credit->closed !~ /^Y/i
       && $conf->exists('unapplycredits')
       && scalar(@cust_credit_bill)       ) {
    $unapply = qq! (<A HREF="javascript:areyousure('!.
               qq!${p}misc/unapply-cust_credit.cgi?!. $cust_credit->crednum.
               qq!', 'Are you sure you want to unapply this credit?')">!.
               qq!unapply</A>)!;
  }
  
  push @history, {
    'date'   => $cust_credit->_date,
    'desc'   => $pre. "Credit$post by ". $cust_credit->otaker.
                ' ('. $cust_credit->reason. ')'.
                "$desc$apply$delete$unapply",
    'credit' => $cust_credit->amount,
  };

}

#refunds
foreach my $cust_refund ($cust_main->cust_refund) {

  my $payby = $cust_refund->payby;
  my $payinfo = $payby eq 'CARD'
                  ? $cust_refund->payinfo_masked
                  : $cust_refund->payinfo;

  $payby =~ s/^BILL$/Check #/ if $payinfo;
  $payby =~ s/^CHEK$/Electronic check /;
  $payby =~ s/^(CARD|COMP)$/$1 /;

  push @history, {
    'date'   => $cust_refund->_date,
    'desc'   => "Refund ($payby$payinfo) by ". $cust_refund->otaker,
    'refund' => $cust_refund->refund,
  };

}

%>

<%= table() %>
<TR>
  <TH>Date</TH>
  <TH>Description</TH>
  <TH><FONT SIZE=-1>Charge</FONT></TH>
  <TH><FONT SIZE=-1>Payment</FONT></TH>
  <TH><FONT SIZE=-1>In-house<BR>Credit</FONT></TH>
  <TH><FONT SIZE=-1>Refund</FONT></TH>
  <TH><FONT SIZE=-1>Balance</FONT></TH>
</TR>

<%
#display payment history

my %target;
my $balance = 0;
foreach my $item ( sort { $a->{'date'} <=> $b->{'date'} } @history ) {

  my $charge  = exists($item->{'charge'})
                  ? sprintf('$%.2f', $item->{'charge'})
                  : '';
  my $payment = exists($item->{'payment'})
                  ? sprintf('-&nbsp;$%.2f', $item->{'payment'})
                  : '';
  $payment ||= sprintf('<DEL>-&nbsp;$%.2f</DEL>', $item->{'void_payment'})
    if exists($item->{'void_payment'});
  my $credit  = exists($item->{'credit'})
                  ? sprintf('-&nbsp;$%.2f', $item->{'credit'})
                  : '';
  my $refund  = exists($item->{'refund'})
                  ? sprintf('$%.2f', $item->{'refund'})
                  : '';

  my $target = exists($item->{'target'}) ? $item->{'target'} : '';

  $balance += $item->{'charge'}  if exists $item->{'charge'};
  $balance -= $item->{'payment'} if exists $item->{'payment'};
  $balance -= $item->{'credit'}  if exists $item->{'credit'};
  $balance += $item->{'refund'}  if exists $item->{'refund'};
  $balance = sprintf("%.2f", $balance);
  $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
  ( my $showbalance = '$'. $balance ) =~ s/^\$\-/-&nbsp;\$/;

%>

  <TR>
    <TD>
      <% unless ( !$target || $target{$target}++ ) { %>
        <A NAME="<%= $target %>">
      <% } %>
      <%= time2str("%D",$item->{'date'}) %>
      <% if ( $target && $target{$target} == 1 ) { %>
        </A>
      <% } %>
      </FONT>
    </TD>
    <TD><%= $item->{'desc'} %></TD>
    <TD ALIGN="right"><%= $charge  %></TD>
    <TD ALIGN="right"><%= $payment %></TD>
    <TD ALIGN="right"><%= $credit  %></TD>
    <TD ALIGN="right"><%= $refund  %></TD>
    <TD ALIGN="right"><%= $showbalance %></TD>
  </TR>

<% } %>

</TABLE>


--- NEW FILE: order_pkg.html ---
<%
  my( $cust_main ) = @_;
%>

<SCRIPT TYPE="text/javascript">
function enable_order_pkg () {
  if ( document.OrderPkgForm.pkgpart.selectedIndex > 0 ) {
    document.OrderPkgForm.submit.disabled = false;
  } else {
    document.OrderPkgForm.submit.disabled = true;
  }
}
</SCRIPT>

<FORM NAME="OrderPkgForm" ACTION="<%= $p %>edit/process/quick-cust_pkg.cgi" METHOD="POST">

<INPUT TYPE="hidden" NAME="custnum" VALUE="<%= $cust_main->custnum %>">

<SELECT NAME="pkgpart" onChange="enable_order_pkg()"><OPTION>Order additional package

<%
foreach my $part_pkg (
  qsearch( 'part_pkg', { 'disabled' => '' }, '',
           ' AND 0 < ( SELECT COUNT(*) FROM type_pkgs '.
           '             WHERE typenum = '. $cust_main->agent->typenum.
           '             AND type_pkgs.pkgpart = part_pkg.pkgpart )'
         )
) {
%>

  <OPTION VALUE="<%= $part_pkg->pkgpart %>"><%= $part_pkg->pkg %> - <%= $part_pkg->comment %>

<% } %>

</SELECT>

<INPUT NAME="submit" TYPE="submit" VALUE="Order Package" disabled>

</FORM>




More information about the freeside-commits mailing list