remove
[freeside.git] / httemplate / view / cust_main.cgi
1 <!-- $Id: cust_main.cgi,v 1.19 2002-01-30 14:18:09 ivan Exp $ -->
2 <%
3
4 my $conf = new FS::Conf;
5
6 print header("Customer View", menubar(
7   'Main Menu' => popurl(2)
8 ));
9
10 die "No customer specified (bad URL)!" unless $cgi->keywords;
11 my($query) = $cgi->keywords; # needs parens with my, ->keywords returns array
12 $query =~ /^(\d+)$/;
13 my $custnum = $1;
14 my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
15 die "Customer not found!" unless $cust_main;
16
17 print qq!<A HREF="!, popurl(2), 
18       qq!edit/cust_main.cgi?$custnum">Edit this customer</A>!;
19 print qq! | <A HREF="!, popurl(2), 
20       qq!misc/delete-customer.cgi?$custnum"> Delete this customer</A>!
21   if $conf->exists('deletecustomers');
22
23 unless ( $conf->exists('disable_customer_referrals') ) {
24   print qq! | <A HREF="!, popurl(2),
25         qq!edit/cust_main.cgi?referral_custnum=$custnum">!,
26         qq!Refer a new customer</A>!;
27
28   print qq! | <A HREF="!, popurl(2),
29         qq!search/cust_main.cgi?referral_custnum=$custnum">!,
30         qq!View this customer's referrals</A>!;
31 }
32
33 print '<BR><BR>';
34
35 my $signupurl = $conf->config('signupurl');
36 if ( $signupurl ) {
37 print "This customer's signup URL: ".
38       "<a href=\"$signupurl?ref=$custnum\">$signupurl?ref=$custnum</a><BR><BR>";
39 }
40
41 print '<A NAME="cust_main"></A>';
42
43 print &itable(), '<TR>';
44
45 print '<TD VALIGN="top">';
46
47   print "Billing address", &ntable("#cccccc"), "<TR><TD>",
48         &ntable("#cccccc",2),
49     '<TR><TD ALIGN="right">Contact name</TD>',
50       '<TD COLSPAN=3 BGCOLOR="#ffffff">',
51       $cust_main->last, ', ', $cust_main->first,
52       '</TD><TD ALIGN="right">SS#</TD><TD BGCOLOR="#ffffff">',
53       $cust_main->ss || '&nbsp', '</TD></TR>',
54     '<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
55       $cust_main->company,
56       '</TD></TR>',
57     '<TR><TD ALIGN="right">Address</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
58       $cust_main->address1,
59       '</TD></TR>',
60   ;
61   print '<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
62         $cust_main->address2, '</TD></TR>'
63     if $cust_main->address2;
64   print '<TR><TD ALIGN="right">City</TD><TD BGCOLOR="#ffffff">',
65           $cust_main->city,
66           '</TD><TD ALIGN="right">State</TD><TD BGCOLOR="#ffffff">',
67           $cust_main->state,
68           '</TD><TD ALIGN="right">Zip</TD><TD BGCOLOR="#ffffff">',
69           $cust_main->zip, '</TD></TR>',
70         '<TR><TD ALIGN="right">Country</TD><TD BGCOLOR="#ffffff">',
71           $cust_main->country,
72           '</TD></TR>',
73   ;
74   print '<TR><TD ALIGN="right">Day Phone</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
75           $cust_main->daytime || '&nbsp', '</TD></TR>',
76        '<TR><TD ALIGN="right">Night Phone</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
77           $cust_main->night || '&nbsp', '</TD></TR>',
78         '<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
79           $cust_main->fax || '&nbsp', '</TD></TR>',
80         '</TABLE>', "</TD></TR></TABLE>"
81   ;
82
83   if ( defined $cust_main->dbdef_table->column('ship_last') ) {
84
85     my $pre = $cust_main->ship_last ? 'ship_' : '';
86
87     print "<BR>Service address", &ntable("#cccccc"), "<TR><TD>",
88           &ntable("#cccccc",2),
89       '<TR><TD ALIGN="right">Contact name</TD>',
90         '<TD COLSPAN=5 BGCOLOR="#ffffff">',
91         $cust_main->get("${pre}last"), ', ', $cust_main->get("${pre}first"),
92         '</TD></TR>',
93       '<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
94         $cust_main->get("${pre}company"),
95         '</TD></TR>',
96       '<TR><TD ALIGN="right">Address</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
97         $cust_main->get("${pre}address1"),
98         '</TD></TR>',
99     ;
100     print '<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
101           $cust_main->get("${pre}address2"), '</TD></TR>'
102       if $cust_main->get("${pre}address2");
103     print '<TR><TD ALIGN="right">City</TD><TD BGCOLOR="#ffffff">',
104             $cust_main->get("${pre}city"),
105             '</TD><TD ALIGN="right">State</TD><TD BGCOLOR="#ffffff">',
106             $cust_main->get("${pre}state"),
107             '</TD><TD ALIGN="right">Zip</TD><TD BGCOLOR="#ffffff">',
108             $cust_main->get("${pre}zip"), '</TD></TR>',
109           '<TR><TD ALIGN="right">Country</TD><TD BGCOLOR="#ffffff">',
110             $cust_main->get("${pre}country"),
111             '</TD></TR>',
112     ;
113     print '<TR><TD ALIGN="right">Day Phone</TD>',
114           '<TD COLSPAN=5 BGCOLOR="#ffffff">',
115             $cust_main->get("${pre}daytime") || '&nbsp', '</TD></TR>',
116           '<TR><TD ALIGN="right">Night Phone</TD>'.
117           '<TD COLSPAN=5 BGCOLOR="#ffffff">',
118             $cust_main->get("${pre}night") || '&nbsp', '</TD></TR>',
119           '<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
120             $cust_main->get("${pre}fax") || '&nbsp', '</TD></TR>',
121           '</TABLE>', "</TD></TR></TABLE>"
122     ;
123
124   }
125
126 print '</TD>';
127
128 print '<TD VALIGN="top">';
129
130   print &ntable("#cccccc"), "<TR><TD>", &ntable("#cccccc",2),
131         '<TR><TD ALIGN="right">Customer number</TD><TD BGCOLOR="#ffffff">',
132         $custnum, '</TD></TR>',
133   ;
134
135   my @agents = qsearch( 'agent', {} );
136   my $agent;
137   unless ( scalar(@agents) == 1 ) {
138     $agent = qsearchs('agent',{ 'agentnum' => $cust_main->agentnum } );
139     print '<TR><TD ALIGN="right">Agent</TD><TD BGCOLOR="#ffffff">',
140         $agent->agentnum, ": ", $agent->agent, '</TD></TR>';
141   } else {
142     $agent = $agents[0];
143   }
144   my @referrals = qsearch( 'part_referral', {} );
145   unless ( scalar(@referrals) == 1 ) {
146     my $referral = qsearchs('part_referral', {
147       'refnum' => $cust_main->refnum
148     } );
149     print '<TR><TD ALIGN="right">Referral</TD><TD BGCOLOR="#ffffff">',
150           $referral->refnum, ": ", $referral->referral, '</TD></TR>';
151   }
152   print '<TR><TD ALIGN="right">Order taker</TD><TD BGCOLOR="#ffffff">',
153     $cust_main->otaker, '</TD></TR>';
154
155   print '<TR><TD ALIGN="right">Referring Customer</TD><TD BGCOLOR="#ffffff">';
156   my $referring_cust_main = '';
157   if ( $cust_main->referral_custnum
158        && ( $referring_cust_main =
159             qsearchs('cust_main', { custnum => $cust_main->referral_custnum } )
160           )
161      ) {
162     print '<A HREF="'. popurl(1). 'cust_main.cgi?'.
163           $cust_main->referral_custnum. '">'.
164           $cust_main->referral_custnum. ': '.
165           ( $referring_cust_main->company
166               ? $referring_cust_main->company. ' ('.
167                   $referring_cust_main->last. ', '. $referring_cust_main->first.
168                   ')'
169               : $referring_cust_main->last. ', '. $referring_cust_main->first
170           ).
171           '</A>';
172   }
173   print '</TD></TR>';
174
175   print '</TABLE></TD></TR></TABLE>';
176
177 print '<BR>';
178
179   my @invoicing_list = $cust_main->invoicing_list;
180   print "Billing information (",
181        qq!<A HREF="!, popurl(2), qq!misc/bill.cgi?$custnum">!, "Bill now</A>)",
182         &ntable("#cccccc"), "<TR><TD>", &ntable("#cccccc",2),
183         '<TR><TD ALIGN="right">Tax exempt</TD><TD BGCOLOR="#ffffff">',
184         $cust_main->tax ? 'yes' : 'no',
185         '</TD></TR>',
186         '<TR><TD ALIGN="right">Postal invoices</TD><TD BGCOLOR="#ffffff">',
187         ( grep { $_ eq 'POST' } @invoicing_list ) ? 'yes' : 'no',
188         '</TD></TR>',
189         '<TR><TD ALIGN="right">Email invoices</TD><TD BGCOLOR="#ffffff">',
190         join(', ', grep { $_ ne 'POST' } @invoicing_list ) || 'no',
191         '</TD></TR>',
192         '<TR><TD ALIGN="right">Billing type</TD><TD BGCOLOR="#ffffff">',
193   ;
194
195   if ( $cust_main->payby eq 'CARD' ) {
196     print 'Credit card</TD></TR>',
197           '<TR><TD ALIGN="right">Card number</TD><TD BGCOLOR="#ffffff">',
198           $cust_main->payinfo, '</TD></TR>',
199           '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
200           $cust_main->paydate, '</TD></TR>',
201           '<TR><TD ALIGN="right">Name on card</TD><TD BGCOLOR="#ffffff">',
202           $cust_main->payname, '</TD></TR>'
203     ;
204   } elsif ( $cust_main->payby eq 'BILL' ) {
205     print 'Billing</TD></TR>';
206     print '<TR><TD ALIGN="right">P.O. </TD><TD BGCOLOR="#ffffff">',
207           $cust_main->payinfo, '</TD></TR>',
208       if $cust_main->payinfo;
209     print '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
210           $cust_main->paydate, '</TD></TR>',
211           '<TR><TD ALIGN="right">Attention</TD><TD BGCOLOR="#ffffff">',
212           $cust_main->payname, '</TD></TR>',
213     ;
214   } elsif ( $cust_main->payby eq 'COMP' ) {
215     print 'Complimentary</TD></TR>',
216           '<TR><TD ALIGN="right">Authorized by</TD><TD BGCOLOR="#ffffff">',
217           $cust_main->payinfo, '</TD></TR>',
218           '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
219           $cust_main->paydate, '</TD></TR>',
220     ;
221   }
222
223   print "</TABLE></TD></TR></TABLE>";
224
225 print '</TD></TR></TABLE>';
226
227 if ( defined $cust_main->dbdef_table->column('comments')
228      && $cust_main->comments )
229 {
230   print "<BR>Comments", &ntable("#cccccc"), "<TR><TD>",
231         &ntable("#cccccc",2),
232         '<TR><TD BGCOLOR="#ffffff"><PRE>', $cust_main->comments,
233         '</PRE></TD></TR></TABLE></TABLE>';
234 }
235
236 print '</TD></TR></TABLE>';
237
238 print '<BR>'.
239   '<FORM ACTION="'.popurl(2).'edit/process/quick-cust_pkg.cgi" METHOD="POST">'.
240   qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!.
241   '<SELECT NAME="pkgpart"><OPTION> ';
242
243 foreach my $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) {
244   my $pkgpart = $type_pkgs->pkgpart;
245 #  my $part_pkg = qsearchs('part_pkg', { 'pkgpart' => $pkgpart } )
246 #    or do { warn "unknown type_pkgs.pkgpart $pkgpart"; next; };
247   my $part_pkg =
248     qsearchs('part_pkg', { 'pkgpart' => $pkgpart, 'disabled' => '' } )
249     or next;
250   print qq!<OPTION VALUE="$pkgpart">!. $part_pkg->pkg. ' - '.
251         $part_pkg->comment;
252 }
253
254 print '</SELECT><INPUT TYPE="submit" VALUE="Order Package"><BR>';
255
256 print qq!<BR><A NAME="cust_pkg">Packages</A> !,
257 #      qq!<BR>Click on package number to view/edit package.!,
258       qq!( <A HREF="!, popurl(2), qq!edit/cust_pkg.cgi?$custnum">Order and cancel packages</A> (preserves services) )!,
259 ;
260
261 #display packages
262
263 #formatting
264 print qq!!, &table(), "\n",
265       qq!<TR><TH COLSPAN=2 ROWSPAN=2>Package</TH><TH COLSPAN=5>!,
266       qq!Dates</TH><TH COLSPAN=2 ROWSPAN=2>Services</TH></TR>\n!,
267       qq!<TR><TH><FONT SIZE=-1>Setup</FONT></TH><TH>!,
268       qq!<FONT SIZE=-1>Next bill</FONT>!,
269       qq!</TH><TH><FONT SIZE=-1>Susp.</FONT></TH><TH><FONT SIZE=-1>Expire!,
270       qq!</FONT></TH>!,
271       qq!<TH><FONT SIZE=-1>Cancel</FONT></TH>!,
272       qq!</TR>\n!;
273
274 #get package info
275 my @packages;
276 if ( $conf->exists('hidecancelledpackages') ) {
277   @packages = sort { $a->pkgnum <=> $b->pkgnum } ($cust_main->ncancelled_pkgs);
278 } else {
279   @packages = sort { $a->pkgnum <=> $b->pkgnum } ($cust_main->all_pkgs);
280 }
281
282 my $n1 = '<TR>';
283 foreach my $package (@packages) {
284   my $pkgnum = $package->pkgnum;
285   my $pkg = $package->part_pkg->pkg;
286   my $comment = $package->part_pkg->comment;
287   my $pkgview = popurl(2). "view/cust_pkg.cgi?$pkgnum";
288   my @cust_svc = qsearch( 'cust_svc', { 'pkgnum' => $pkgnum } );
289   my $rowspan = scalar(@cust_svc) || 1;
290
291   my $button_cgi = new CGI;
292   $button_cgi->param('clone', $package->part_pkg->pkgpart);
293   $button_cgi->param('pkgnum', $package->pkgnum);
294   my $button_url = popurl(2). "edit/part_pkg.cgi?". $button_cgi->query_string;
295
296   #print $n1, qq!<TD ROWSPAN=$rowspan><A HREF="$pkgview">$pkgnum</A></TD>!,
297   print $n1, qq!<TD ROWSPAN=$rowspan>$pkgnum</TD>!,
298         qq!<TD ROWSPAN=$rowspan><FONT SIZE=-1>!,
299         #qq!<A HREF="$pkgview">$pkg - $comment</A>!,
300         qq!$pkg - $comment!,
301         qq! ( <A HREF="$pkgview">Edit</A> | <A HREF="$button_url">Customize pricing</A> )</FONT></TD>!,
302   ;
303   for ( qw( setup bill susp expire cancel ) ) {
304     print "<TD ROWSPAN=$rowspan><FONT SIZE=-1>", ( $package->getfield($_)
305             ? time2str("%D", $package->getfield($_) )
306             :  '&nbsp'
307           ), '</FONT></TD>',
308     ;
309   }
310
311   my $n2 = '';
312   foreach my $cust_svc ( @cust_svc ) {
313      my($label, $value, $svcdb) = $cust_svc->label;
314      my($svcnum) = $cust_svc->svcnum;
315      my($sview) = popurl(2). "view";
316      print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
317            qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
318      $n2="</TR><TR>";
319   }
320   $n1="</TR><TR>";
321 }  
322 print "</TR>";
323
324 #formatting
325 print "</TABLE>";
326
327 #formatting
328 print qq!<BR><BR><A NAME="history">Payment History!.
329       qq!</A> ( !.
330       qq!<A HREF="!. popurl(2). qq!edit/cust_pay.cgi?custnum=$custnum">!.
331       qq!Post payment</A> | !.
332       qq!<A HREF="!. popurl(2). qq!edit/cust_credit.cgi?$custnum">!.
333       qq!Post credit</A> )!;
334
335 #get payment history
336 #
337 # major problem: this whole thing is way too sloppy.
338 # minor problem: the description lines need better formatting.
339
340 my @history = (); #needed for mod_perl :)
341
342 my %target = ();
343
344 my @bills = qsearch('cust_bill',{'custnum'=>$custnum});
345 foreach my $bill (@bills) {
346   my($bref)=$bill->hashref;
347   my $bpre = ( $bill->owed > 0 )
348                ? '<b><font size="+1" color="#ff0000"> Open '
349                : '';
350   my $bpost = ( $bill->owed > 0 ) ? '</font></b>' : '';
351   push @history,
352     $bref->{_date} . qq!\t<A HREF="!. popurl(2). qq!view/cust_bill.cgi?! .
353     $bref->{invnum} . qq!">${bpre}Invoice #! . $bref->{invnum} .
354     qq! (Balance \$! . $bill->owed . qq!)$bpost</A>\t! .
355     $bref->{charged} . qq!\t\t\t!;
356
357   my(@cust_bill_pay)=qsearch('cust_bill_pay',{'invnum'=> $bref->{invnum} } );
358 #  my(@payments)=qsearch('cust_pay',{'invnum'=> $bref->{invnum} } );
359 #  my($payment);
360 #  foreach $payment (@payments) {
361   foreach my $cust_bill_pay (@cust_bill_pay) {
362     my $payment = $cust_bill_pay->cust_pay;
363     my($date,$invnum,$payby,$payinfo,$paid)=($payment->_date,
364                                              $cust_bill_pay->invnum,
365                                              $payment->payby,
366                                              $payment->payinfo,
367                                              $cust_bill_pay->amount,
368                       );
369     $payinfo = substr($payinfo,0,4). 'x'x(length($payinfo)-4)
370       if $payby eq 'CARD';
371     my $target = "$payby$payinfo";
372     $payby =~ s/^BILL$/Check #/ if $payinfo;
373     $payby =~ s/^(CARD|COMP)$/$1 /;
374     push @history,
375       "$date\tPayment, Invoice #$invnum ($payby$payinfo)\t\t$paid\t\t\t$target";
376   }
377
378   my(@cust_credit_bill)=
379     qsearch('cust_credit_bill', { 'invnum'=> $bref->{invnum} } );
380   foreach my $cust_credit_bill (@cust_credit_bill) {
381     my $cust_credit = $cust_credit_bill->cust_credit;
382     my($date, $invnum, $crednum, $amount, $reason, $app_date ) = (
383       $cust_credit->_date,
384       $cust_credit_bill->invnum,
385       $cust_credit_bill->crednum,
386       $cust_credit_bill->amount,
387       $cust_credit->reason,
388       time2str("%D", $cust_credit_bill->_date),
389     );
390     push @history,
391       "$date\tCredit #$crednum: $reason<BR>".
392       "(applied to invoice #$invnum on $app_date)\t\t\t$amount\t";
393   }
394 }
395
396 my @credits = grep { $_->credited > 0 }
397            qsearch('cust_credit',{'custnum'=>$custnum});
398 foreach my $credit (@credits) {
399   my($cref)=$credit->hashref;
400   push @history,
401     $cref->{_date} . "\t" .
402     qq!<A HREF="! . popurl(2). qq!edit/cust_credit_bill.cgi?!. $cref->{crednum} . qq!">!.
403     '<b><font size="+1" color="#ff0000">Unapplied credit #' .
404     $cref->{crednum} . "</font></b></A>: ".
405     $cref->{reason} . "\t\t\t" . $credit->credited . "\t";
406 }
407
408 my(@refunds)=qsearch('cust_refund',{'custnum'=> $custnum } );
409 foreach my $refund (@refunds) {
410   my($rref)=$refund->hashref;
411   my($refundnum) = (
412     $refund->refundnum,
413   );
414
415   push @history,
416     $rref->{_date} . "\tRefund #$refundnum, (" .
417     $rref->{payby} . " " . $rref->{payinfo} . ") by " .
418     $rref->{otaker} . " - ". $rref->{reason} . "\t\t\t\t" .
419     $rref->{refund};
420 }
421
422 my @unapplied_payments =
423   grep { $_->unapplied > 0 } qsearch('cust_pay', { 'custnum' => $custnum } );
424 foreach my $payment (@unapplied_payments) {
425   my $payby = $payment->payby;
426   my $payinfo = $payment->payinfo;
427   #false laziness w/above
428   $payinfo = substr($payinfo,0,4). 'x'x(length($payinfo)-4)
429     if $payby eq 'CARD';
430   my $target = "$payby$payinfo";
431   $payby =~ s/^BILL$/Check #/ if $payinfo;
432   $payby =~ s/^(CARD|COMP)$/$1 /;
433   push @history,
434     $payment->_date. "\t".
435     '<A HREF="'. popurl(2). 'edit/cust_bill_pay.cgi?'. $payment->paynum. '">'.
436     '<b><font size="+1" color="#ff0000">Unapplied payment #' .
437     $payment->paynum . " ($payby$payinfo)</font></b></A>".
438     "\t\t" . $payment->unapplied . "\t\t\t$target";
439 }
440
441         #formatting
442         print &table(), <<END;
443 <TR>
444   <TH>Date</TH>
445   <TH>Description</TH>
446   <TH><FONT SIZE=-1>Charge</FONT></TH>
447   <TH><FONT SIZE=-1>Payment</FONT></TH>
448   <TH><FONT SIZE=-1>In-house<BR>Credit</FONT></TH>
449   <TH><FONT SIZE=-1>Refund</FONT></TH>
450   <TH><FONT SIZE=-1>Balance</FONT></TH>
451 </TR>
452 END
453
454 #display payment history
455
456 my $balance = 0;
457 foreach my $item (sort keyfield_numerically @history) {
458   my($date,$desc,$charge,$payment,$credit,$refund,$target)=split(/\t/,$item);
459   $charge ||= 0;
460   $payment ||= 0;
461   $credit ||= 0;
462   $refund ||= 0;
463   $balance += $charge - $payment;
464   $balance -= $credit - $refund;
465   $balance = sprintf("%.2f", $balance);
466   $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
467   $target = '' unless defined $target;
468
469   print "<TR><TD><FONT SIZE=-1>";
470   print qq!<A NAME="$target">! unless $target && $target{$target}++;
471   print time2str("%D",$date);
472   print '</A>' if $target && $target{$target} == 1;
473   print "</FONT></TD>",
474         "<TD><FONT SIZE=-1>$desc</FONT></TD>",
475         "<TD><FONT SIZE=-1>",
476         ( $charge ? "\$".sprintf("%.2f",$charge) : '' ),
477         "</FONT></TD>",
478         "<TD><FONT SIZE=-1>",
479         ( $payment ? "- \$".sprintf("%.2f",$payment) : '' ),
480         "</FONT></TD>",
481         "<TD><FONT SIZE=-1>",
482         ( $credit ? "- \$".sprintf("%.2f",$credit) : '' ),
483         "</FONT></TD>",
484         "<TD><FONT SIZE=-1>",
485         ( $refund ? "\$".sprintf("%.2f",$refund) : '' ),
486         "</FONT></TD>",
487         "<TD><FONT SIZE=-1>\$" . $balance,
488         "</FONT></TD>",
489         "\n";
490 }
491
492 #formatting
493 print "</TABLE>";
494
495 #end
496
497 #formatting
498 print <<END;
499
500   </BODY>
501 </HTML>
502 END
503
504 #subroutiens
505 sub keyfield_numerically { (split(/\t/,$a))[0] <=> (split(/\t/,$b))[0] ; }
506
507 %>