%
my $conf = new FS::Conf;
#false laziness with view/cust_pkg.cgi, but i'm trying to make that go away so
my %uiview = ();
my %uiadd = ();
foreach my $part_svc ( qsearch('part_svc',{}) ) {
$uiview{$part_svc->svcpart} = popurl(2). "view/". $part_svc->svcdb . ".cgi";
$uiadd{$part_svc->svcpart}= popurl(2). "edit/". $part_svc->svcdb . ".cgi";
}
print header("Customer View", menubar(
'Main Menu' => popurl(2)
));
%>
<%
die "No customer specified (bad URL)!" unless $cgi->keywords;
my($query) = $cgi->keywords; # needs parens with my, ->keywords returns array
$query =~ /^(\d+)$/;
my $custnum = $1;
my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
die "Customer not found!" unless $cust_main;
print qq!Edit this customer!;
%>
<%
print qq! | !.
'Cancel this customer'
if $cust_main->ncancelled_pkgs;
print qq! | !.
'Delete this customer'
if $conf->exists('deletecustomers');
unless ( $conf->exists('disable_customer_referrals') ) {
print qq! | !,
qq!Refer a new customer!;
print qq! | !,
qq!View this customer's referrals!;
}
print '
';
my $signupurl = $conf->config('signupurl');
if ( $signupurl ) {
print "This customer's signup URL: ".
"$signupurl?ref=$custnum
";
}
print '';
print &itable(), '
';
print '';
print "Billing address", &ntable("#cccccc"), " |
",
&ntable("#cccccc",2),
' |
Contact name | ',
'',
$cust_main->last, ', ', $cust_main->first,
' | ';
print 'SS# | ',
$cust_main->ss || ' ', ' | '
if $conf->exists('show_ss');
print '
',
'Company | ',
$cust_main->company,
' |
',
'Address | ',
$cust_main->address1,
' |
',
;
print ' | ',
$cust_main->address2, ' |
'
if $cust_main->address2;
print 'City | ',
$cust_main->city,
' | State | ',
$cust_main->state,
' | Zip | ',
$cust_main->zip, ' |
',
'Country | ',
$cust_main->country,
' |
',
;
my $daytime_label = FS::Msgcat::_gettext('daytime') || 'Day Phone';
my $night_label = FS::Msgcat::_gettext('night') || 'Night Phone';
print ''. $daytime_label.
' | ',
$cust_main->daytime || ' ', ' |
',
''. $night_label.
' | ',
$cust_main->night || ' ', ' |
',
'Fax | ',
$cust_main->fax || ' ', ' |
',
'', ""
;
if ( defined $cust_main->dbdef_table->column('ship_last') ) {
my $pre = $cust_main->ship_last ? 'ship_' : '';
print "
Service address", &ntable("#cccccc"), "",
&ntable("#cccccc",2),
' |
Contact name | ',
'',
$cust_main->get("${pre}last"), ', ', $cust_main->get("${pre}first"),
' |
',
'Company | ',
$cust_main->get("${pre}company"),
' |
',
'Address | ',
$cust_main->get("${pre}address1"),
' |
',
;
print ' | ',
$cust_main->get("${pre}address2"), ' |
'
if $cust_main->get("${pre}address2");
print 'City | ',
$cust_main->get("${pre}city"),
' | State | ',
$cust_main->get("${pre}state"),
' | Zip | ',
$cust_main->get("${pre}zip"), ' |
',
'Country | ',
$cust_main->get("${pre}country"),
' |
',
;
print ''. $daytime_label. ' | ',
'',
$cust_main->get("${pre}daytime") || ' ', ' |
',
''. $night_label. ' | '.
'',
$cust_main->get("${pre}night") || ' ', ' |
',
'Fax | ',
$cust_main->get("${pre}fax") || ' ', ' |
',
'', ""
;
}
print '';
print '';
print &ntable("#cccccc"), " | ", &ntable("#cccccc",2),
' |
Customer number | ',
$custnum, ' |
',
;
my @agents = qsearch( 'agent', {} );
my $agent;
unless ( scalar(@agents) == 1 ) {
$agent = qsearchs('agent',{ 'agentnum' => $cust_main->agentnum } );
print 'Agent | ',
$agent->agentnum, ": ", $agent->agent, ' |
';
} else {
$agent = $agents[0];
}
my @referrals = qsearch( 'part_referral', {} );
unless ( scalar(@referrals) == 1 ) {
my $referral = qsearchs('part_referral', {
'refnum' => $cust_main->refnum
} );
print 'Advertising source | ',
$referral->refnum, ": ", $referral->referral, ' |
';
}
print 'Order taker | ',
$cust_main->otaker, ' |
';
print 'Referring Customer | ';
my $referring_cust_main = '';
if ( $cust_main->referral_custnum
&& ( $referring_cust_main =
qsearchs('cust_main', { custnum => $cust_main->referral_custnum } )
)
) {
print ''.
$cust_main->referral_custnum. ': '.
( $referring_cust_main->company
? $referring_cust_main->company. ' ('.
$referring_cust_main->last. ', '. $referring_cust_main->first.
')'
: $referring_cust_main->last. ', '. $referring_cust_main->first
).
'';
}
print ' |
';
print '';
print '
';
if ( $conf->config('payby-default') ne 'HIDE' ) {
my @invoicing_list = $cust_main->invoicing_list;
print "Billing information (",
qq!!, "Bill now)",
&ntable("#cccccc"), "", &ntable("#cccccc",2),
' |
Tax exempt | ',
$cust_main->tax ? 'yes' : 'no',
' |
',
'Postal invoices | ',
( grep { $_ eq 'POST' } @invoicing_list ) ? 'yes' : 'no',
' |
',
'Email invoices | ',
join(', ', grep { $_ ne 'POST' } @invoicing_list ) || 'no',
' |
',
'Billing type | ',
;
if ( $cust_main->payby eq 'CARD' || $cust_main->payby eq 'DCRD' ) {
my $payinfo = $cust_main->payinfo;
$payinfo = 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
print 'Credit card ',
( $cust_main->payby eq 'CARD' ? '(automatic)' : '(on-demand)' ),
' |
',
'Card number | ',
$payinfo, ' |
',
'Expiration | ',
$cust_main->paydate, ' |
',
'Name on card | ',
$cust_main->payname, ' |
'
;
} elsif ( $cust_main->payby eq 'CHEK' || $cust_main->payby eq 'DCHK') {
my( $account, $aba ) = split('@', $cust_main->payinfo );
print 'Electronic check ',
( $cust_main->payby eq 'CHEK' ? '(automatic)' : '(on-demand)' ),
'',
'Account number | ',
$account, ' |
',
'ABA/Routing code | ',
$aba, ' |
',
'Bank name | ',
$cust_main->payname, ' |
'
;
} elsif ( $cust_main->payby eq 'LECB' ) {
$cust_main->payinfo =~ /^(\d{3})(\d{3})(\d{4})$/;
my $payinfo = "$1-$2-$3";
print 'Phone bill billing',
'Phone number | ',
$payinfo, ' |
',
;
} elsif ( $cust_main->payby eq 'BILL' ) {
print 'Billing';
print 'P.O. | ',
$cust_main->payinfo, ' |
',
if $cust_main->payinfo;
print 'Expiration | ',
$cust_main->paydate, ' |
',
'Attention | ',
$cust_main->payname, ' |
',
;
} elsif ( $cust_main->payby eq 'COMP' ) {
print 'Complimentary',
'Authorized by | ',
$cust_main->payinfo, ' |
',
'Expiration | ',
$cust_main->paydate, ' |
',
;
}
print "";
}
print '';
if ( defined $cust_main->dbdef_table->column('comments')
&& $cust_main->comments =~ /[^\s\n\r]/ )
{
print "
Comments". &ntable("#cccccc"). "".
&ntable("#cccccc",2).
' |
'.
encode_entities($cust_main->comments).
' |
';
}
print '';
print '
'.
'
';
if ( $conf->config('payby-default') ne 'HIDE' ) {
print
qq!
!;
}
%>
<%
print qq!Packages !,
qq!( Order and cancel packages (preserves services) )!,
;
#begin display packages
#get package info
my $packages = get_packages($cust_main, $conf);
if ( @$packages ) {
%>
Package |
Status |
Services |
<%
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});
}
}
%>
>
<%=$pkg->{pkgnum}%>:
<%=$pkg->{pkg}%> - <%=$pkg->{comment}%>
<% unless ($pkg->{cancel}) { %>
( <%=pkg_change_link($pkg)%> )
( <%=pkg_dates_link($pkg)%> | <%=pkg_customize_link($pkg,$custnum)%> )
<% } %>
|
<%
#foreach (qw(setup last_bill next_bill susp expire cancel)) {
# print qq! ! . pkg_datestr($pkg,$_,$conf) . qq! | \n!;
#}
print "". &itable('');
sub freq {
#false laziness w/edit/part_pkg.cgi
my %freq = ( #move this
'1d' => 'daily',
'1w' => 'weekly',
'2w' => 'biweekly (every 2 weeks)',
'1' => 'monthly',
'2' => 'bimonthly (every 2 months)',
'3' => 'quarterly (every 3 months)',
'6' => 'semiannually (every 6 months)',
'12' => 'annually',
'24' => 'biannually (every 2 years)',
);
my $freq = shift;
exists $freq{$freq} ? $freq{$freq} : "every $freq months";
}
#eomove
if ( $pkg->{cancel} ) { #status: cancelled
print ' |
Cancelled | '.
''. pkg_datestr($pkg,'cancel',$conf). ' |
';
unless ( $pkg->{setup} ) {
print 'Never billed |
';
} else {
print "Setup | ".
pkg_datestr($pkg, 'setup',$conf). ' |
';
print "Last bill | ".
pkg_datestr($pkg, 'last_bill',$conf). ' |
'
if $pkg->{'last_bill'};
print "Suspended | ".
pkg_datestr($pkg, 'susp',$conf). ' |
'
if $pkg->{'susp'};
}
} else {
if ( $pkg->{susp} ) { #status: suspended
print 'Suspended | '.
''. pkg_datestr($pkg,'susp',$conf). ' |
';
unless ( $pkg->{setup} ) {
print 'Never billed |
';
} else {
print "Setup | ".
pkg_datestr($pkg, 'setup',$conf). ' |
';
}
print "Last bill | ".
pkg_datestr($pkg, 'last_bill',$conf). ' |
'
if $pkg->{'last_bill'};
# next bill ??
print "Expires | ".
pkg_datestr($pkg, 'expire',$conf). ' |
'
if $pkg->{'expire'};
print '( '. pkg_unsuspend_link($pkg).
' | '. pkg_cancel_link($pkg). ' ) |
';
} else { #status: active
unless ( $pkg->{setup} ) { #not setup
print 'Not yet billed (';
unless ( $pkg->{freq} ) {
print 'one-time charge) |
';
print '( '. pkg_cancel_link($pkg).
' ) | ';
} else {
print 'billed '. freq($pkg->{freq}). ')
';
}
} else { #setup
unless ( $pkg->{freq} ) {
print "One-time charge |
".
'Billed | '.
pkg_datestr($pkg,'setup',$conf). ' |
';
} else {
print 'Active'.
', billed '. freq($pkg->{freq}). ' |
'.
'Setup | '.
pkg_datestr($pkg, 'setup',$conf). ' |
';
}
}
print "Last bill | ".
pkg_datestr($pkg, 'last_bill',$conf). ' |
'
if $pkg->{'last_bill'};
print "Next bill | ".
pkg_datestr($pkg, 'next_bill',$conf). ' |
'
if $pkg->{'next_bill'};
print "Expires | ".
pkg_datestr($pkg, 'expire',$conf). ' |
'
if $pkg->{'expire'};
if ( $pkg->{freq} ) {
print '( '. pkg_suspend_link($pkg).
' | '. pkg_cancel_link($pkg). ' ) |
';
}
}
}
print "
\n";
if ($rowspan == 0) { print qq!\n!; next; }
my $cnt = 0;
foreach my $svcpart (sort {$a->{svcpart} <=> $b->{svcpart}} @{$pkg->{svcparts}}) {
foreach my $service (@{$svcpart->{services}}) {
print '' if ($cnt > 0);
%>
<%=svc_link($svcpart,$service)%> |
<%=svc_label_link($svcpart,$service)%> ( <%=svc_unprovision_link($service)%> ) |
<%
$cnt++;
}
if ($svcpart->{count} < $svcpart->{quantity}) {
print qq!\n! if ($cnt > 0);
print qq! !.svc_provision_link($pkg, $svcpart, $conf).qq! | \n
\n!;
}
}
}
print '';
}
#end display packages
%>
<% if ( $conf->config('payby-default') ne 'HIDE' ) { %>
Payment History
(Post payment
| Post credit)
<%
#get payment history
my @history = ();
#invoices
foreach my $cust_bill ($cust_main->cust_bill) {
my $pre = ( $cust_bill->owed > 0 )
? 'Open '
: '';
my $post = ( $cust_bill->owed > 0 ) ? '' : '';
my $invnum = $cust_bill->invnum;
push @history, {
'date' => $cust_bill->_date,
'desc' => qq!!. $pre.
"Invoice #$invnum (Balance \$". $cust_bill->owed. ')'.
$post. '',
'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 = $cust_pay->payinfo;
my @cust_bill_pay = $cust_pay->cust_bill_pay;
$payinfo = 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4))
if $payby eq 'CARD';
my $target = "$payby$payinfo";
$payby =~ s/^BILL$/Check #/ if $payinfo;
$payby =~ s/^BILL$//;
$payby =~ s/^(CARD|COMP)$/$1 /;
my $info = $payby ? " ($payby$payinfo)" : '';
my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
if ( scalar(@cust_bill_pay) == 0 ) {
#completely unapplied
$pre = 'Unapplied ';
$post = '';
$apply = qq! (apply)';
} elsif ( scalar(@cust_bill_pay) == 1 && $cust_pay->unapplied == 0 ) {
#applied to one invoice
$desc = ' applied to Invoice #'. $cust_bill_pay[0]->invnum;
} else {
#complicated
$desc = '
';
foreach my $cust_bill_pay (@cust_bill_pay) {
$desc .= ' '.
'$'. $cust_bill_pay->amount.
' applied to Invoice #'. $cust_bill_pay->invnum.
'
';
#' on '. time2str("%D", $cust_bill_pay->_date).
}
if ( $cust_pay->unapplied > 0 ) {
$desc .= ' '.
'$'.
$cust_pay->unapplied. ' unapplied'.
qq! (apply)'.
'
';
}
}
my $delete = '';
if ( $cust_pay->closed !~ /^Y/i && $conf->exists('deletepayments') ) {
$delete = qq! (delete)!;
}
my $unapply = '';
if ( $cust_pay->closed !~ /^Y/i
&& $conf->exists('unapplypayments')
&& scalar(@cust_bill_pay) ) {
$unapply = qq! (unapply)!;
}
push @history, {
'date' => $cust_pay->_date,
'desc' => $pre. "Payment$post$info$desc".
"$apply$delete$unapply",
'payment' => $cust_pay->paid,
'target' => $target,
};
}
#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 = 'Unapplied ';
$post = '';
$apply = qq! (apply)';
} elsif ( scalar(@cust_credit_bill) == 1
&& scalar(@cust_credit_refund) == 0
&& $cust_credit->credited == 0 ) {
#applied to one invoice
$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 = '
';
foreach my $app ( sort { $a->_date <=> $b->_date }
( @cust_credit_bill, @cust_credit_refund ) ) {
if ( $app->isa('FS::cust_credit_bill') ) {
$desc .= ' '.
'$'. $app->amount.
' applied to Invoice #'. $app->invnum.
'
';
#' on '. time2str("%D", $app->_date).
} elsif ( $app->isa('FS::cust_credit_refund') ) {
$desc .= ' '.
'$'. $app->amount.
' refunded on'. time2str("%D", $app->_date).
'
';
} else {
die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund";
}
}
if ( $cust_credit->credited > 0 ) {
$desc .= ' - $'.
$cust_credit->unapplied. ' unapplied'.
qq! (apply'.
'
';
}
}
#
my $delete = '';
if ( $cust_credit->closed !~ /^Y/i && $conf->exists('deletecredits') ) {
$delete = qq! (delete)!;
}
my $unapply = '';
if ( $cust_credit->closed !~ /^Y/i
&& $conf->exists('unapplycredits')
&& scalar(@cust_credit_bill) ) {
$unapply = qq! (unapply)!;
}
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 = $cust_refund->payinfo;
$payinfo = 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4))
if $payby eq 'CARD';
$payby =~ s/^BILL$/Check #/ if $payinfo;
$payby =~ s/^(CARD|COMP)$/$1 /;
push @history, {
'date' => $cust_refund->_date,
'desc' => "Refund ($payby$payinfo) by ". $cust_refund->otaker,
'refund' => $cust_refund->refund,
};
}
%>
<%= table() %>
Date |
Description |
Charge |
Payment |
In-house Credit |
Refund |
Balance |
<%
#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('- $%.2f', $item->{'payment'})
: '';
my $credit = exists($item->{'credit'})
? sprintf('- $%.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/^\$\-/- \$/;
%>
<% unless ( !$target || $target{$target}++ ) { %>
<% } %>
<%= time2str("%D",$item->{'date'}) %>
<% if ( $target && $target{$target} == 1 ) { %>
<% } %>
|
<%= $item->{'desc'} %> |
<%= $charge %> |
<%= $payment %> |
<%= $credit %> |
<%= $refund %> |
<%= $showbalance %> |
<% } %>
<% } %>