summaryrefslogtreecommitdiff
path: root/htdocs
diff options
context:
space:
mode:
Diffstat (limited to 'htdocs')
-rw-r--r--htdocs/.htaccess3
-rwxr-xr-xhtdocs/browse/agent.cgi100
-rwxr-xr-xhtdocs/browse/agent_type.cgi68
-rwxr-xr-xhtdocs/browse/cust_main_county.cgi75
-rwxr-xr-xhtdocs/browse/part_pkg.cgi69
-rwxr-xr-xhtdocs/browse/part_referral.cgi65
-rwxr-xr-xhtdocs/browse/part_svc.cgi91
-rwxr-xr-xhtdocs/browse/svc_acct_pop.cgi72
-rwxr-xr-xhtdocs/docs/CGI-modules-2.76-patch.txt23
-rw-r--r--htdocs/docs/billing.html2
-rw-r--r--htdocs/docs/config.html28
-rw-r--r--htdocs/docs/export.html31
-rw-r--r--htdocs/docs/index.html8
-rw-r--r--htdocs/docs/install.html54
-rw-r--r--htdocs/docs/legacy.html4
-rw-r--r--htdocs/docs/man/Bill.txt29
-rw-r--r--htdocs/docs/man/CGI.txt47
-rw-r--r--htdocs/docs/man/Conf.txt47
-rw-r--r--htdocs/docs/man/FS.html247
-rw-r--r--htdocs/docs/man/FS/Bill.html32
-rw-r--r--htdocs/docs/man/FS/CGI.html115
-rw-r--r--htdocs/docs/man/FS/Conf.html94
-rw-r--r--htdocs/docs/man/FS/Invoice.html32
-rw-r--r--htdocs/docs/man/FS/Record.html380
-rw-r--r--htdocs/docs/man/FS/SSH.html104
-rw-r--r--htdocs/docs/man/FS/UI/Base.html117
-rw-r--r--htdocs/docs/man/FS/UI/CGI.html115
-rw-r--r--htdocs/docs/man/FS/UI/Gtk.html112
-rw-r--r--htdocs/docs/man/FS/UI/agent.html0
-rw-r--r--htdocs/docs/man/FS/UID.html160
-rw-r--r--htdocs/docs/man/FS/agent.html130
-rw-r--r--htdocs/docs/man/FS/agent_type.html138
-rw-r--r--htdocs/docs/man/FS/cust_bill.html184
-rw-r--r--htdocs/docs/man/FS/cust_bill_pkg.html119
-rw-r--r--htdocs/docs/man/FS/cust_credit.html126
-rw-r--r--htdocs/docs/man/FS/cust_main.html277
-rw-r--r--htdocs/docs/man/FS/cust_main_county.html113
-rw-r--r--htdocs/docs/man/FS/cust_main_invoice.html128
-rw-r--r--htdocs/docs/man/FS/cust_pay.html116
-rw-r--r--htdocs/docs/man/FS/cust_pay_batch.html134
-rw-r--r--htdocs/docs/man/FS/cust_pkg.html254
-rw-r--r--htdocs/docs/man/FS/cust_refund.html116
-rw-r--r--htdocs/docs/man/FS/cust_svc.html134
-rw-r--r--htdocs/docs/man/FS/dbdef.html97
-rw-r--r--htdocs/docs/man/FS/dbdef_colgroup.html86
-rw-r--r--htdocs/docs/man/FS/dbdef_column.html118
-rw-r--r--htdocs/docs/man/FS/dbdef_index.html58
-rw-r--r--htdocs/docs/man/FS/dbdef_table.html144
-rw-r--r--htdocs/docs/man/FS/dbdef_unique.html58
-rw-r--r--htdocs/docs/man/FS/part_pkg.html152
-rw-r--r--htdocs/docs/man/FS/part_referral.html113
-rw-r--r--htdocs/docs/man/FS/part_svc.html121
-rw-r--r--htdocs/docs/man/FS/pkg_svc.html125
-rw-r--r--htdocs/docs/man/FS/svc_Common.html109
-rw-r--r--htdocs/docs/man/FS/svc_acct.html210
-rw-r--r--htdocs/docs/man/FS/svc_acct_pop.html115
-rw-r--r--htdocs/docs/man/FS/svc_acct_sm.html172
-rw-r--r--htdocs/docs/man/FS/svc_domain.html196
-rw-r--r--htdocs/docs/man/FS/type_pkgs.html109
-rw-r--r--htdocs/docs/man/Invoice.txt23
-rw-r--r--htdocs/docs/man/Record.txt332
-rw-r--r--htdocs/docs/man/SSH.txt63
-rw-r--r--htdocs/docs/man/UID.txt79
-rw-r--r--htdocs/docs/man/agent.txt65
-rw-r--r--htdocs/docs/man/agent_type.txt72
-rw-r--r--htdocs/docs/man/cust_bill.txt140
-rw-r--r--htdocs/docs/man/cust_bill_pkg.txt72
-rw-r--r--htdocs/docs/man/cust_credit.txt75
-rw-r--r--htdocs/docs/man/cust_main.txt200
-rw-r--r--htdocs/docs/man/cust_main_county.txt67
-rw-r--r--htdocs/docs/man/cust_pay.txt66
-rw-r--r--htdocs/docs/man/cust_pkg.txt150
-rw-r--r--htdocs/docs/man/cust_refund.txt66
-rw-r--r--htdocs/docs/man/cust_svc.txt72
-rw-r--r--htdocs/docs/man/dbdef.txt80
-rw-r--r--htdocs/docs/man/dbdef_colgroup.txt51
-rw-r--r--htdocs/docs/man/dbdef_column.txt69
-rw-r--r--htdocs/docs/man/dbdef_index.txt27
-rw-r--r--htdocs/docs/man/dbdef_table.txt94
-rw-r--r--htdocs/docs/man/dbdef_unique.txt27
-rw-r--r--htdocs/docs/man/index.html48
-rw-r--r--htdocs/docs/man/part_pkg.txt73
-rw-r--r--htdocs/docs/man/part_referral.txt63
-rw-r--r--htdocs/docs/man/part_svc.txt69
-rw-r--r--htdocs/docs/man/pkg_svc.txt61
-rw-r--r--htdocs/docs/man/svc_acct.txt168
-rw-r--r--htdocs/docs/man/svc_acct_pop.txt65
-rw-r--r--htdocs/docs/man/svc_acct_sm.txt121
-rw-r--r--htdocs/docs/man/svc_domain.txt131
-rw-r--r--htdocs/docs/man/type_pkgs.txt55
-rwxr-xr-xhtdocs/docs/postgresql.html23
-rw-r--r--htdocs/docs/schema.html26
-rw-r--r--htdocs/docs/signup.html47
-rw-r--r--htdocs/docs/trouble.html21
-rw-r--r--htdocs/docs/upgrade2.html4
-rw-r--r--htdocs/docs/upgrade3.html40
-rw-r--r--htdocs/docs/upgrade4.html27
-rw-r--r--htdocs/docs/upgrade5.html34
-rwxr-xr-xhtdocs/edit/agent.cgi77
-rwxr-xr-xhtdocs/edit/agent_type.cgi93
-rwxr-xr-xhtdocs/edit/cust_credit.cgi100
-rwxr-xr-xhtdocs/edit/cust_main.cgi455
-rwxr-xr-xhtdocs/edit/cust_main_county-expand.cgi79
-rwxr-xr-xhtdocs/edit/cust_main_county.cgi60
-rwxr-xr-xhtdocs/edit/cust_pay.cgi79
-rwxr-xr-xhtdocs/edit/cust_pkg.cgi150
-rwxr-xr-xhtdocs/edit/part_pkg.cgi156
-rwxr-xr-xhtdocs/edit/part_referral.cgi68
-rwxr-xr-xhtdocs/edit/part_svc.cgi138
-rwxr-xr-xhtdocs/edit/process/agent.cgi56
-rwxr-xr-xhtdocs/edit/process/agent_type.cgi73
-rwxr-xr-xhtdocs/edit/process/cust_credit.cgi78
-rwxr-xr-xhtdocs/edit/process/cust_main.cgi216
-rwxr-xr-xhtdocs/edit/process/cust_main_county-expand.cgi72
-rwxr-xr-xhtdocs/edit/process/cust_main_county.cgi46
-rwxr-xr-xhtdocs/edit/process/cust_pay.cgi74
-rwxr-xr-xhtdocs/edit/process/cust_pkg.cgi77
-rwxr-xr-xhtdocs/edit/process/part_pkg.cgi128
-rwxr-xr-xhtdocs/edit/process/part_referral.cgi60
-rwxr-xr-xhtdocs/edit/process/part_svc.cgi60
-rwxr-xr-xhtdocs/edit/process/svc_acct.cgi97
-rwxr-xr-xhtdocs/edit/process/svc_acct_pop.cgi55
-rwxr-xr-xhtdocs/edit/process/svc_acct_sm.cgi73
-rwxr-xr-xhtdocs/edit/process/svc_domain.cgi72
-rwxr-xr-xhtdocs/edit/svc_acct.cgi193
-rwxr-xr-xhtdocs/edit/svc_acct_pop.cgi81
-rwxr-xr-xhtdocs/edit/svc_acct_sm.cgi156
-rwxr-xr-xhtdocs/edit/svc_domain.cgi160
-rwxr-xr-xhtdocs/images/sisd.jpgbin22122 -> 0 bytes
-rwxr-xr-xhtdocs/index.html42
-rwxr-xr-xhtdocs/misc/bill.cgi66
-rwxr-xr-xhtdocs/misc/cancel-unaudited.cgi77
-rwxr-xr-xhtdocs/misc/cancel_pkg.cgi45
-rwxr-xr-xhtdocs/misc/delete-customer.cgi58
-rwxr-xr-xhtdocs/misc/expire_pkg.cgi66
-rwxr-xr-xhtdocs/misc/link.cgi63
-rwxr-xr-xhtdocs/misc/print-invoice.cgi66
-rwxr-xr-xhtdocs/misc/process/delete-customer.cgi46
-rwxr-xr-xhtdocs/misc/process/link.cgi68
-rwxr-xr-xhtdocs/misc/susp_pkg.cgi64
-rwxr-xr-xhtdocs/misc/unsusp_pkg.cgi61
-rwxr-xr-xhtdocs/search/cust_bill.cgi48
-rwxr-xr-xhtdocs/search/cust_main-payinfo.html11
-rwxr-xr-xhtdocs/search/cust_main.cgi225
-rwxr-xr-xhtdocs/search/cust_main.html18
-rwxr-xr-xhtdocs/search/cust_pkg.cgi87
-rwxr-xr-xhtdocs/search/svc_acct.cgi115
-rwxr-xr-xhtdocs/search/svc_acct_sm.cgi150
-rwxr-xr-xhtdocs/search/svc_domain.cgi165
-rwxr-xr-xhtdocs/view/cust_bill.cgi76
-rwxr-xr-xhtdocs/view/cust_main.cgi439
-rwxr-xr-xhtdocs/view/cust_pkg.cgi199
-rwxr-xr-xhtdocs/view/svc_acct.cgi201
-rwxr-xr-xhtdocs/view/svc_acct_sm.cgi159
-rwxr-xr-xhtdocs/view/svc_domain.cgi117
155 files changed, 9899 insertions, 5357 deletions
diff --git a/htdocs/.htaccess b/htdocs/.htaccess
new file mode 100644
index 000000000..f8c6b9c0c
--- /dev/null
+++ b/htdocs/.htaccess
@@ -0,0 +1,3 @@
+AuthName Freeside
+AuthType Basic
+require valid-user
diff --git a/htdocs/browse/agent.cgi b/htdocs/browse/agent.cgi
index cf5f2281f..b73d17b76 100755
--- a/htdocs/browse/agent.cgi
+++ b/htdocs/browse/agent.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# agent.cgi: browse agent
+# $Id: agent.cgi,v 1.13 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 97-dec-12
#
@@ -13,36 +13,93 @@
# agent type was linking to wrong cgi ivan@sisd.com 98-jul-18
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: agent.cgi,v $
+# Revision 1.13 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.12 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.11 1999/01/20 09:43:16 ivan
+# comment out future UI code (but look at it, it's neat!)
+#
+# Revision 1.10 1999/01/19 05:13:24 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.9 1999/01/18 09:41:14 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.8 1999/01/18 09:22:26 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.7 1998/12/17 05:25:16 ivan
+# fix visual and other bugs
+#
+# Revision 1.6 1998/11/23 05:29:46 ivan
+# use CGI::Carp
+#
+# Revision 1.5 1998/11/23 05:27:31 ivan
+# to eliminate warnings
+#
+# Revision 1.4 1998/11/20 08:50:36 ivan
+# s/CGI::Base/CGI.pm, visual fixes
+#
+# Revision 1.3 1998/11/08 10:11:02 ivan
+# CGI.pm
+#
+# Revision 1.2 1998/11/07 10:24:22 ivan
+# don't use depriciated FS::Bill and FS::Invoice, other miscellania
+#
use strict;
-use CGI::Base;
+use vars qw( $ui $cgi $p $agent );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup swapuid);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar table popurl);
+use FS::agent;
+use FS::agent_type;
+
+#Begin silliness
+#
+#use FS::UI::CGI;
+#use FS::UI::agent;
+#
+#$ui = new FS::UI::agent;
+#$ui->browse;
+#exit;
+#__END__
+#End silliness
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-print header('Agent Listing', menubar(
- 'Main Menu' => '../',
- 'Add new agent' => '../edit/agent.cgi'
+$p = popurl(2);
+
+print $cgi->header( '-expires' => 'now' ), header('Agent Listing', menubar(
+ 'Main Menu' => $p,
+ 'Agent Types' => $p. 'browse/agent_type.cgi',
+# 'Add new agent' => '../edit/agent.cgi'
)), <<END;
- <BR>
- Click on agent number to edit.
- <TABLE BORDER>
+Agents are resellers of your service. Agents may be limited to a subset of your
+full offerings (via their type).<BR><BR>
+END
+print &table(), <<END;
<TR>
- <TH><FONT SIZE=-1>Agent #</FONT></TH>
- <TH>Agent</TH>
+ <TH COLSPAN=2>Agent</TH>
<TH>Type</TH>
<TH><FONT SIZE=-1>Freq. (unimp.)</FONT></TH>
<TH><FONT SIZE=-1>Prog. (unimp.)</FONT></TH>
</TR>
END
+# <TH><FONT SIZE=-1>Agent #</FONT></TH>
+# <TH>Agent</TH>
-my($agent);
foreach $agent ( sort {
$a->getfield('agentnum') <=> $b->getfield('agentnum')
} qsearch('agent',{}) ) {
@@ -52,10 +109,11 @@ foreach $agent ( sort {
my($atype)=$agent_type->getfield('atype');
print <<END;
<TR>
- <TD><A HREF="../edit/agent.cgi?$hashref->{agentnum}">
+ <TD><A HREF="${p}edit/agent.cgi?$hashref->{agentnum}">
$hashref->{agentnum}</A></TD>
- <TD>$hashref->{agent}</TD>
- <TD><A HREF="../edit/agent_type.cgi?$typenum">$atype</A></TD>
+ <TD><A HREF="${p}edit/agent.cgi?$hashref->{agentnum}">
+ $hashref->{agent}</A></TD>
+ <TD><A HREF="${p}edit/agent_type.cgi?$typenum">$atype</A></TD>
<TD>$hashref->{freq}</TD>
<TD>$hashref->{prog}</TD>
</TR>
@@ -64,8 +122,12 @@ END
}
print <<END;
+ <TR>
+ <TD COLSPAN=2><A HREF="${p}edit/agent.cgi"><I>Add new agent</I></A></TD>
+ <TD><A HREF="${p}edit/agent_type.cgi"><I>Add new agent type</I></A></TD>
+ </TR>
</TABLE>
- </CENTER>
+
</BODY>
</HTML>
END
diff --git a/htdocs/browse/agent_type.cgi b/htdocs/browse/agent_type.cgi
index 5f05bd514..9d8687299 100755
--- a/htdocs/browse/agent_type.cgi
+++ b/htdocs/browse/agent_type.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# agent_type.cgi: browse agent_type
+# $Id: agent_type.cgi,v 1.8 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 97-dec-10
#
@@ -9,34 +9,58 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: agent_type.cgi,v $
+# Revision 1.8 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.7 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.6 1999/04/07 11:10:46 ivan
+# harmless typo
+#
+# Revision 1.5 1999/01/19 05:13:25 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:15 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/17 05:25:17 ivan
+# fix visual and other bugs
+#
+# Revision 1.2 1998/11/21 07:39:52 ivan
+# visual
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $p $agent_type );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup swapuid);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl table);
+use FS::agent_type;
+use FS::type_pkgs;
+use FS::part_pkg;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-
-print header("Agent Type Listing", menubar(
- 'Main Menu' => '../',
- 'Add new agent type' => "../edit/agent_type.cgi",
-)), <<END;
- <BR>Click on agent type number to edit.
- <TABLE BORDER>
+$p = popurl(2);
+print $cgi->header( '-expires' => 'now' ), header("Agent Type Listing", menubar(
+ 'Main Menu' => $p,
+)), "Agent types define groups of packages that you can then assign to".
+ " particular agents.<BR><BR>", &table(), <<END;
<TR>
- <TH><FONT SIZE=-1>Type #</FONT></TH>
- <TH>Type</TH>
- <TH colspan="2">Packages</TH>
+ <TH COLSPAN=2>Agent Type</TH>
+ <TH COLSPAN="2">Packages</TH>
</TR>
END
-my($agent_type);
foreach $agent_type ( sort {
$a->getfield('typenum') <=> $b->getfield('typenum')
} qsearch('agent_type',{}) ) {
@@ -46,10 +70,10 @@ foreach $agent_type ( sort {
$rowspan = int($rowspan/2+0.5) ;
print <<END;
<TR>
- <TD ROWSPAN=$rowspan><A HREF="../edit/agent_type.cgi?$hashref->{typenum}">
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/agent_type.cgi?$hashref->{typenum}">
$hashref->{typenum}
</A></TD>
- <TD ROWSPAN=$rowspan>$hashref->{atype}</TD>
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/agent_type.cgi?$hashref->{typenum}">$hashref->{atype}</A></TD>
END
my($type_pkgs);
@@ -59,7 +83,7 @@ END
my($part_pkg) = qsearchs('part_pkg',{'pkgpart'=> $pkgpart });
print qq!<TR>! if ($tdcount == 0) ;
$tdcount = 0 if ($tdcount == -1) ;
- print qq!<TD><A HREF="../edit/part_pkg.cgi?$pkgpart">!,
+ print qq!<TD><A HREF="${p}edit/part_pkg.cgi?$pkgpart">!,
$part_pkg->getfield('pkg'),"</A></TD>";
$tdcount ++ ;
if ($tdcount == 2)
@@ -73,8 +97,8 @@ END
}
print <<END;
- </TR></TABLE>
- </CENTER>
+ <TR><TD COLSPAN=2><I><A HREF="${p}edit/agent_type.cgi">Add new agent type</A></I></TD></TR>
+ </TABLE>
</BODY>
</HTML>
END
diff --git a/htdocs/browse/cust_main_county.cgi b/htdocs/browse/cust_main_county.cgi
index d615198c9..5f2b13dc0 100755
--- a/htdocs/browse/cust_main_county.cgi
+++ b/htdocs/browse/cust_main_county.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# cust_main_county.cgi: browse cust_main_county
+# $Id: cust_main_county.cgi,v 1.7 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 97-dec-13
#
@@ -8,46 +8,85 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: cust_main_county.cgi,v $
+# Revision 1.7 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.6 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.5 1999/01/19 05:13:26 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:16 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/17 05:25:18 ivan
+# fix visual and other bugs
+#
+# Revision 1.2 1998/11/18 09:01:34 ivan
+# i18n! i18n!
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $p $cust_main_county );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup swapuid);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl table);
+use FS::cust_main_county;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-print header("Tax Rate Listing", menubar(
- 'Main Menu' => '../',
- 'Edit tax rates' => "../edit/cust_main_county.cgi",
+$p = popurl(2);
+
+print $cgi->header( '-expires' => 'now' ), header("Tax Rate Listing", menubar(
+ 'Main Menu' => $p,
+ 'Edit tax rates' => $p. "edit/cust_main_county.cgi",
)),<<END;
- <BR>Click on <u>expand</u> to specify tax rates by county.
- <P><TABLE BORDER>
+ Click on <u>expand country</u> to specify a country's tax rates by state.
+ <BR>Click on <u>expand state</u> to specify a state's tax rates by county.
+ <BR><BR>
+END
+print &table(), <<END;
<TR>
+ <TH><FONT SIZE=-1>Country</FONT></TH>
<TH><FONT SIZE=-1>State</FONT></TH>
<TH>County</TH>
<TH><FONT SIZE=-1>Tax</FONT></TH>
</TR>
END
-my($cust_main_county);
foreach $cust_main_county ( qsearch('cust_main_county',{}) ) {
my($hashref)=$cust_main_county->hashref;
print <<END;
<TR>
- <TD>$hashref->{state}</TD>
+ <TD>$hashref->{country}</TD>
END
-
- print "<TD>", $hashref->{county}
- ? $hashref->{county}
+ print "<TD>", $hashref->{state}
+ ? $hashref->{state}
: qq!(ALL) <FONT SIZE=-1>!.
- qq!<A HREF="../edit/cust_main_county-expand.cgi?!. $hashref->{taxnum}.
- qq!">expand</A></FONT>!
+ qq!<A HREF="${p}edit/cust_main_county-expand.cgi?!. $hashref->{taxnum}.
+ qq!">expand country</A></FONT>!
, "</TD>";
+ print "<TD>";
+ if ( $hashref->{county} ) {
+ print $hashref->{county};
+ } else {
+ print "(ALL)";
+ if ( $hashref->{state} ) {
+ print qq!<FONT SIZE=-1>!.
+ qq!<A HREF="${p}edit/cust_main_county-expand.cgi?!. $hashref->{taxnum}.
+ qq!">expand state</A></FONT>!;
+ }
+ }
+ print "</TD>";
print <<END;
<TD>$hashref->{tax}%</TD>
diff --git a/htdocs/browse/part_pkg.cgi b/htdocs/browse/part_pkg.cgi
index e5ff31e9e..d4c359b28 100755
--- a/htdocs/browse/part_pkg.cgi
+++ b/htdocs/browse/part_pkg.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# part_svc.cgi: browse part_pkg
+# $Id: part_pkg.cgi,v 1.8 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 97-dec-5,9
#
@@ -8,29 +8,57 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: part_pkg.cgi,v $
+# Revision 1.8 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.7 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.6 1999/01/19 05:13:27 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:17 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1998/12/17 05:25:19 ivan
+# fix visual and other bugs
+#
+# Revision 1.3 1998/11/21 07:23:45 ivan
+# visual
+#
+# Revision 1.2 1998/11/21 07:00:32 ivan
+# visual
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $p $part_pkg );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup swapuid);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl table);
+use FS::part_pkg;
+use FS::pkg_svc;
+use FS::part_svc;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
+$p = popurl(2);
-print header("Package Part Listing",menubar(
- 'Main Menu' => '../',
- 'Add new package' => "../edit/part_pkg.cgi",
-)), <<END;
- <BR>Click on package part number to edit.
+print $cgi->header( '-expires' => 'now' ), header("Package Part Listing",menubar(
+ 'Main Menu' => $p,
+)), "One or more services are grouped together into a package and given",
+ " pricing information. Customers purchase packages, not services.<BR><BR>",
+ &table(), <<END;
<TABLE BORDER>
<TR>
- <TH><FONT SIZE=-1>Part #</FONT></TH>
- <TH>Package</TH>
+ <TH COLSPAN=2>Package</TH>
<TH>Comment</TH>
<TH><FONT SIZE=-1>Setup Fee</FONT></TH>
<TH><FONT SIZE=-1>Freq.</FONT></TH>
@@ -40,7 +68,6 @@ print header("Package Part Listing",menubar(
</TR>
END
-my($part_pkg);
foreach $part_pkg ( sort {
$a->getfield('pkgpart') <=> $b->getfield('pkgpart')
} qsearch('part_pkg',{}) ) {
@@ -50,10 +77,10 @@ foreach $part_pkg ( sort {
my($rowspan)=scalar(@pkg_svc);
print <<END;
<TR>
- <TD ROWSPAN=$rowspan><A HREF="../edit/part_pkg.cgi?$hashref->{pkgpart}">
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/part_pkg.cgi?$hashref->{pkgpart}">
$hashref->{pkgpart}
</A></TD>
- <TD ROWSPAN=$rowspan>$hashref->{pkg}</TD>
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/part_pkg.cgi?$hashref->{pkgpart}">$hashref->{pkg}</A></TD>
<TD ROWSPAN=$rowspan>$hashref->{comment}</TD>
<TD ROWSPAN=$rowspan>$hashref->{setup}</TD>
<TD ROWSPAN=$rowspan>$hashref->{freq}</TD>
@@ -61,20 +88,22 @@ foreach $part_pkg ( sort {
END
my($pkg_svc);
+ my($n)="";
foreach $pkg_svc ( @pkg_svc ) {
my($svcpart)=$pkg_svc->getfield('svcpart');
my($part_svc) = qsearchs('part_svc',{'svcpart'=> $svcpart });
- print qq!<TD><A HREF="../edit/part_svc.cgi?$svcpart">!,
+ print $n,qq!<TD><A HREF="${p}edit/part_svc.cgi?$svcpart">!,
$part_svc->getfield('svc'),"</A></TD><TD>",
- $pkg_svc->getfield('quantity'),"</TD></TR><TR>\n";
+ $pkg_svc->getfield('quantity'),"</TD></TR>\n";
+ $n="<TR>";
}
print "</TR>";
}
print <<END;
- </TR></TABLE>
- </CENTER>
+ <TR><TD COLSPAN=2><I><A HREF="${p}edit/part_pkg.cgi">Add new package</A></I></TD></TR>
+ </TABLE>
</BODY>
</HTML>
END
diff --git a/htdocs/browse/part_referral.cgi b/htdocs/browse/part_referral.cgi
index b16fa896d..e4ca25a65 100755
--- a/htdocs/browse/part_referral.cgi
+++ b/htdocs/browse/part_referral.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# part_referral.cgi: Browse part_referral
+# $Id: part_referral.cgi,v 1.9 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 98-feb-23
#
@@ -8,47 +8,78 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: part_referral.cgi,v $
+# Revision 1.9 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.8 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.7 1999/01/19 05:13:28 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 09:41:18 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.5 1998/12/17 05:25:20 ivan
+# fix visual and other bugs
+#
+# Revision 1.4 1998/12/17 04:32:55 ivan
+# print $cgi->header
+#
+# Revision 1.3 1998/12/17 04:31:36 ivan
+# use CGI::Carp
+#
+# Revision 1.2 1998/12/17 04:26:04 ivan
+# use CGI; no relative URLs
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $p $part_referral );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup swapuid);
use FS::Record qw(qsearch);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl table);
+use FS::part_referral;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-print header("Referral Listing", menubar(
- 'Main Menu' => '../',
- 'Add new referral' => "../edit/part_referral.cgi",
-)), <<END;
- <BR>Click on referral number to edit.
- <TABLE BORDER>
+$p = popurl(2);
+
+print $cgi->header( '-expires' => 'now' ), header("Referral Listing", menubar(
+ 'Main Menu' => $p,
+# 'Add new referral' => "../edit/part_referral.cgi",
+)), "Where a customer heard about your service. Tracked for informational purposes.<BR><BR>", &table(), <<END;
<TR>
- <TH><FONT SIZE=-1>Referral #</FONT></TH>
- <TH>Referral</TH>
+ <TH COLSPAN=2>Referral</TH>
</TR>
END
-my($part_referral);
foreach $part_referral ( sort {
$a->getfield('refnum') <=> $b->getfield('refnum')
} qsearch('part_referral',{}) ) {
my($hashref)=$part_referral->hashref;
print <<END;
<TR>
- <TD><A HREF="../edit/part_referral.cgi?$hashref->{refnum}">
+ <TD><A HREF="${p}edit/part_referral.cgi?$hashref->{refnum}">
$hashref->{refnum}</A></TD>
- <TD>$hashref->{referral}</TD>
+ <TD><A HREF="${p}edit/part_referral.cgi?$hashref->{refnum}">
+ $hashref->{referral}</A></TD>
</TR>
END
}
print <<END;
+ <TR>
+ <TD COLSPAN=2><A HREF="${p}edit/part_referral.cgi"><I>Add new referral</I></A></TD>
+ </TR>
</TABLE>
</CENTER>
</BODY>
diff --git a/htdocs/browse/part_svc.cgi b/htdocs/browse/part_svc.cgi
index 71a556421..123cb7d2a 100755
--- a/htdocs/browse/part_svc.cgi
+++ b/htdocs/browse/part_svc.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# part_svc.cgi: browse part_svc
+# $Id: part_svc.cgi,v 1.11 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 97-nov-14, 97-dec-9
#
@@ -8,37 +8,70 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: part_svc.cgi,v $
+# Revision 1.11 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.10 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.9 1999/01/19 05:13:29 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.8 1999/01/18 09:41:19 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.7 1998/12/30 23:06:22 ivan
+# typo
+#
+# Revision 1.6 1998/12/30 23:03:20 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.5 1998/12/17 05:25:21 ivan
+# fix visual and other bugs
+#
+# Revision 1.4 1998/11/21 02:26:22 ivan
+# visual
+#
+# Revision 1.3 1998/11/20 23:10:57 ivan
+# visual
+#
+# Revision 1.2 1998/11/20 08:50:37 ivan
+# s/CGI::Base/CGI.pm, visual fixes
+#
use strict;
-use CGI::Base;
-use FS::UID qw(cgisuidsetup swapuid);
-use FS::Record qw(qsearch);
-use FS::part_svc qw(fields);
-use FS::CGI qw(header menubar);
+use vars qw( $cgi $p $part_svc );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use FS::UID qw(cgisuidsetup);
+use FS::Record qw(qsearch fields);
+use FS::part_svc;
+use FS::CGI qw(header menubar popurl table);
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-print header('Service Part Listing', menubar(
- 'Main Menu' => '../',
- 'Add new service' => "../edit/part_svc.cgi",
+$p = popurl(2);
+
+print $cgi->header( '-expires' => 'now' ), header('Service Part Listing', menubar(
+ 'Main Menu' => $p,
)),<<END;
- <BR>Click on service part number to edit.
- <TABLE BORDER>
+ Services are items you offer to your customers.<BR><BR>
+END
+print &table(), <<END;
<TR>
- <TH>Part #</TH>
- <TH>Service</TH>
+ <TH COLSPAN=2>Service</TH>
<TH>Table</TH>
<TH>Field</TH>
- <TH>Action</TH>
- <TH>Value</TH>
+ <TH COLSPAN=2>Modifier</TH>
</TR>
END
-my($part_svc);
foreach $part_svc ( sort {
$a->getfield('svcpart') <=> $b->getfield('svcpart')
} qsearch('part_svc',{}) ) {
@@ -51,30 +84,34 @@ foreach $part_svc ( sort {
grep /^${svcdb}__/,
fields('part_svc')
;
- my($rowspan)=scalar(@rows);
+ my($rowspan)=scalar(@rows) || 1;
print <<END;
<TR>
- <TD ROWSPAN=$rowspan><A HREF="../edit/part_svc.cgi?$hashref->{svcpart}">
- $hashref->{svcpart}
- </A></TD>
- <TD ROWSPAN=$rowspan>$hashref->{svc}</TD>
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/part_svc.cgi?$hashref->{svcpart}">
+ $hashref->{svcpart}</A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="${p}edit/part_svc.cgi?$hashref->{svcpart}"> $hashref->{svc}</A></TD>
<TD ROWSPAN=$rowspan>$hashref->{svcdb}</TD>
END
+
+ my($n1)='';
my($row);
foreach $row ( @rows ) {
my($flag)=$part_svc->getfield($svcdb.'__'.$row.'_flag');
- print "<TD>$row</TD><TD>";
+ print $n1,"<TD>$row</TD><TD>";
if ( $flag eq "D" ) { print "Default"; }
elsif ( $flag eq "F" ) { print "Fixed"; }
else { print "(Unknown!)"; }
- print "</TD><TD>",$part_svc->getfield($svcdb."__".$row),"</TD></TR><TR>";
+ print "</TD><TD>",$part_svc->getfield($svcdb."__".$row),"</TD>";
+ $n1="</TR><TR>";
}
print "</TR>";
}
print <<END;
+ <TR>
+ <TD COLSPAN=2><A HREF="${p}edit/part_svc.cgi"><I>Add new service</I></A></TD>
+ </TR>
</TABLE>
- </CENTER>
</BODY>
</HTML>
END
diff --git a/htdocs/browse/svc_acct_pop.cgi b/htdocs/browse/svc_acct_pop.cgi
index a8a3a9224..8094a9fd1 100755
--- a/htdocs/browse/svc_acct_pop.cgi
+++ b/htdocs/browse/svc_acct_pop.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# svc_acct_pop.cgi: browse pops
+# $Id: svc_acct_pop.cgi,v 1.8 2000-01-28 22:56:13 ivan Exp $
#
# ivan@sisd.com 98-mar-8
#
@@ -8,53 +8,87 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: svc_acct_pop.cgi,v $
+# Revision 1.8 2000-01-28 22:56:13 ivan
+# track full phone number
+#
+# Revision 1.7 1999/04/09 04:22:34 ivan
+# also table()
+#
+# Revision 1.6 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.5 1999/01/19 05:13:30 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:20 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/17 05:25:22 ivan
+# fix visual and other bugs
+#
+# Revision 1.2 1998/12/17 04:36:59 ivan
+# use CGI;, use CGI::Carp, visual changes, relative URLs
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $p $svc_acct_pop );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup swapuid);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar table popurl);
+use FS::svc_acct_pop;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-print header('POP Listing', menubar(
- 'Main Menu' => '../',
- 'Add new POP' => "../edit/svc_acct_pop.cgi",
-)), <<END;
- <BR>Click on pop number to edit.
- <TABLE BORDER>
+$p = popurl(2);
+
+print $cgi->header( '-expires' => 'now' ), header('POP Listing', menubar(
+ 'Main Menu' => $p,
+)), "Points of Presence<BR><BR>", &table(), <<END;
<TR>
- <TH><FONT SIZE=-1>POP #</FONT></TH>
+ <TH></TH>
<TH>City</TH>
<TH>State</TH>
<TH>Area code</TH>
<TH>Exchange</TH>
+ <TH>Local</TH>
</TR>
END
-my($svc_acct_pop);
foreach $svc_acct_pop ( sort {
$a->getfield('popnum') <=> $b->getfield('popnum')
} qsearch('svc_acct_pop',{}) ) {
my($hashref)=$svc_acct_pop->hashref;
print <<END;
<TR>
- <TD><A HREF="../edit/svc_acct_pop.cgi?$hashref->{popnum}">
+ <TD><A HREF="${p}edit/svc_acct_pop.cgi?$hashref->{popnum}">
$hashref->{popnum}</A></TD>
- <TD>$hashref->{city}</TD>
- <TD>$hashref->{state}</TD>
- <TD>$hashref->{ac}</TD>
- <TD>$hashref->{exch}</TD>
+ <TD><A HREF="${p}edit/svc_acct_pop.cgi?$hashref->{popnum}">
+ $hashref->{city}</A></TD>
+ <TD><A HREF="${p}edit/svc_acct_pop.cgi?$hashref->{popnum}">
+ $hashref->{state}</A></TD>
+ <TD><A HREF="${p}edit/svc_acct_pop.cgi?$hashref->{popnum}">
+ $hashref->{ac}</A></TD>
+ <TD><A HREF="${p}edit/svc_acct_pop.cgi?$hashref->{popnum}">
+ $hashref->{exch}</A></TD>
+ <TD><A HREF="${p}edit/svc_acct_pop.cgi?$hashref->{popnum}">
+ $hashref->{loc}</A></TD>
</TR>
END
}
print <<END;
+ <TR>
+ <TD COLSPAN=5><A HREF="${p}edit/svc_acct_pop.cgi"><I>Add new POP</I></A></TD>
+ </TR>
</TABLE>
</CENTER>
</BODY>
diff --git a/htdocs/docs/CGI-modules-2.76-patch.txt b/htdocs/docs/CGI-modules-2.76-patch.txt
deleted file mode 100755
index 55b50bbbe..000000000
--- a/htdocs/docs/CGI-modules-2.76-patch.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-ivan@rootwood:~/src/CGI-modules-2.76/CGI$ diff -c Base.pm Base.pm.orig
-*** Base.pm Sat Jul 18 00:33:21 1998
---- Base.pm.orig Sat Jul 18 00:06:12 1998
-***************
-*** 938,945 ****
- my $orig_uri = $self->get_uri;
- $self->log("Redirecting $CGI::Base::REQUEST_METHOD $orig_uri to $to_uri")
- if $Debug;
-! my $msg = ($perm) ? StatusHdr(301,"Moved Permanently")
-! : StatusHdr(302,"Moved Temporarily");
- my $hdrs = SendHeaders($msg, LocationHdr($to_uri));
- $self->log($hdrs);
- }
---- 938,945 ----
- my $orig_uri = $self->get_uri;
- $self->log("Redirecting $CGI::Base::REQUEST_METHOD $orig_uri to $to_uri")
- if $Debug;
-! my $msg = ($perm) ? ServerHdr(301,"Moved Permanently")
-! : ServerHdr(302,"Moved Temporarily");
- my $hdrs = SendHeaders($msg, LocationHdr($to_uri));
- $self->log($hdrs);
- }
-
diff --git a/htdocs/docs/billing.html b/htdocs/docs/billing.html
index 02bfbd783..c0354f1ca 100644
--- a/htdocs/docs/billing.html
+++ b/htdocs/docs/billing.html
@@ -3,7 +3,7 @@
</head>
<body>
<h1>Billing</h1>
- The bin/bill script can be run daily to bill all customers. Usage: bill [ -c [ i ] ] [ -d <i>date</i> ] [ -b ]
+ The freeside-bill script can be run daily to bill all customers. Usage: bill [ -c [ i ] ] [ -d <i>date</i> ] [ -b ]
<ul>
<li>-c: Turn on collecting (you probably want this).
<li>-i: Real-time billing (as opposed to bacth billing). Only relevant for credit cards. Not available without modifying site_perl/Bill.pm
diff --git a/htdocs/docs/config.html b/htdocs/docs/config.html
index 9b8002601..cad10ce65 100644
--- a/htdocs/docs/config.html
+++ b/htdocs/docs/config.html
@@ -3,17 +3,39 @@
</head>
<body>
<h1>Configuration files</h1>
-Configuration files and directories are located in `/var/spool/freeside/conf'.
+Configuration file layout has changed in 1.2.x.
+<ul>
+ <li>First, the file `/usr/local/etc/freeside/mapsecrets' is read. Each line
+in this file contains a username and filename, separated by whitespace. Note
+that these are not local usernames - they are passed from Apache (you _did_
+setup <a href="http://www.apache.org/docs/misc/FAQ.html#user-authentication">
+user authetication</a>, correct?). Filenames are located in
+`/usr/local/etc/freeside/'. The specified filename is parsed exactly
+the same as the pre-1.2.x `secrets' file:
+ <li>Three lines: Database engine datasource (for example,
+ `DBI:mysql:freeside' or `DBI:Pg:dbname=freeside'), username, and password.
+ This file should not be world readable. See the DBI manpage and the manpage
+ for your DBD for the exact syntax.
+</ul>
+All further configuration files and directories are located in
+`/usr/local/etc/freeside/conf.<i>datasource</i>', for example,
+`/usr/local/etc/freeside/conf.DBI:Pg:dbname=freeside'
<ul>
<li>address - Your company name and address, four lines.
<li>bsdshellmachines - Your BSD flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd' and `/etc/master.passwd'.
<li>cybercash2 - <a href="http://www.cybercash.com/cybercash/services/cashreg214.html">CyberCash v2</a> support, four lines: paymentserverhost, paymentserverport, paymentserversecret, and transaction type (`mauthonly' or `mauthcapture'). CCLib.pm is required.
<li>cybercash3.2 - <a href="http://www.cybercash.com/cybercash/services/technology.html">CyberCash v3.2</a> support. Two lines: the full path and name of your merchant_conf file, and the transaction type (`mauthonly' or `mauthcapture'). CCMckLib3_2.pm, CCMckDirectLib3_2.pm and CCMckErrno3_2 are required.
+ <li>deletecustomers - The existance of this file will enable customer deletions. Be very careful! Deleting a customer will remove all traces that this customer ever existed! It should probably only be used when auditing a legacy database. Normally, you cancel all of a customers' packages if they cancel service.
<li>domain - Your domain name.
+ <li>editreferrals - The existance of this file will allow you to change the referral of existing customers.
<li>erpcdmachines - Your ERPCD authenticaion machines, one per line. This enables export of `/usr/annex/acp_passwd' and `/usr/annex/acp_dialup'.
+ <li>hidecancelledpackages - The existance of this file will prevent cancelled packages from showing up in listings (though they will still be in the database)
+ <li>hidecancelledcustomers - The existance of this file will prevent customers with only cancelled packages from showing up in listings (though they will still be in the database)
<li>home - For new users, prefixed to usrename to create a directory name. Should have a leading but not a trailing slash.
+ <li>invoice_from - Return address on email invoices.
<li>lpr - Print command for paper invoices, for example `lpr -h'.
<li>nismachines - Your NIS master (not slave master) machines, one per line. This enables export of `/etc/global/passwd' and `/etc/global/shadow'.
+ <li>passwordmin - Minimum password length (default 6);
<li>qmailmachines - Your qmail machines, one per line. This enables export of `/var/qmail/control/virtualdomains', `/var/qmail/control/recipientmap', and `/var/qmail/control/rcpthosts'. The existance of this file (even if empty) also turns on user `.qmail-extension' file maintenance in conjunction with `shellmachine'.
<li>radiusmachines - Your RADIUS authentication machines, one per line. This enables export of `/etc/raddb/users'.
<li>registries - Directory which contains domain registry information. Each registry is a directory.
@@ -27,12 +49,14 @@ Configuration files and directories are located in `/var/spool/freeside/conf'.
<li>registries/internic/to - Email address to which InterNIC domain registrations are sent.
</ul>
</ul>
- <li>secrets - Three lines: Database engine datasource (for example, `DBI:mysql:freeside' or `DBI:Pg:dbname=freeside'), username, and password. This file should not be world readable.
<li>sendmailmachines - Your sendmail machines, one per line. This enables export of `/etc/virtusertable' and `/etc/sendmail.cw'.
<li>shellmachine - A single machine with user home directories mounted. This enables home directory creation, renaming and archiving/deletion. In conjunction with `qmailmachines', it also enables `.qmail-extension' file maintenance.
<li>shellmachines - Your Linux and System V flavored shell (and mail) machines, one per line. This enables export of `/etc/passwd' and `/etc/shadow' files.
<li>shells - Legal shells (think /etc/shells). You probably want to `cut -d: -f7 /etc/passwd | sort | uniq' initially so that importing doesn't fail with `Illegal shell' errors, then remove any special entries afterwords. A blank line specifies that an empty shell is permitted.
+ <li>showpasswords - The existance of this file will allow unencrypted user passwords to be displayed.
<li>smtpmachine - SMTP relay for Freeside's outgoing mail.
+ <li>usernamemin - Minimum username length (default 2);
+ <li>usernamemax - Maximum username length (default is the size of the SQL column, probably specified when fs-setup was run)
</ul>
</body>
diff --git a/htdocs/docs/export.html b/htdocs/docs/export.html
index f760b97dd..86a2b4ccd 100644
--- a/htdocs/docs/export.html
+++ b/htdocs/docs/export.html
@@ -4,29 +4,30 @@
<body>
<h1>File exporting</h1>
<ul>
- <li>bin/svc_acct.export will create UNIX `passwd', `shadow' and `master.passwd' files, ERPCD `acp_passwd' and `acp_dialup' files and a RADIUS `users' file in the `/var/spool/freeside/export' directory. Using the appropriate <a href="config.html">configuration files</a>, you can export these files to your remote machines unattended; see below.
+ <li>bin/svc_acct.export will create UNIX <b>passwd</b>, <b>shadow</b> and <b>master.passwd</b> files, ERPCD <b>acp_passwd</b> and <b>acp_dialup</b> files and a RADIUS <b>users</b> file in the <b>/usr/local/etc/freeside/export.<i>datasrc</i></b> directory. Using the appropriate <a href="config.html">configuration files</a>, you can export these files to your remote machines unattended; see below. Some RADIUS servers (such as <a href="http://www.open.com.au/radiator/">Radiator</a>) will authenticate directly out of an SQL database. In these cases,
+it is reccommended that you copy the svc_acct table to an external RADIUS machine rather than run the RADIUS server on your Freeside machine.
<ul>
- <li>shellmachines - passwd and shadow are copied to the remote machine as /etc/passwd.new and /etc/shadow.net and then moved to /etc/passwd and /etc/shadow if no errors occur.
- <li>bsdshellmachines - passwd and master.passwd are copied to the remote machine as /etc/passwd.new and /etc/master.passwd.new and moved to /etc/passwd and /etc/master.passwd if no errors occur.
- <li>nismachines - passwd and shadow are copied to the `/etc/global' directory on the remote machine. If no errors occur, the command `( cd /var/yp; make; )' is executed on the remote machine.
- <li>erpcdmachines - acp_passwd and acp_dialup are copied to the `/usr/annex' directory on the remote machine. If no errors occur, the command `( kill -USR1 `cat /usr/annex/erpcd.pid` )' is executed on the remote machine.
- <li>radiusmachines - users is copied to the `/etc/raddb' directory on the remote machine. If no errors occur, the command `( builddbm )' is executed on the remote machine.
+ <li>shellmachines - <b>passwd</b> and <b>shadow</b> are copied to the remote machine as <b>/etc/passwd.new</b> and <b>/etc/shadow.new</b> and then moved to <b>/etc/passwd</b> and <b>/etc/shadow</b> if no errors occur.
+ <li>bsdshellmachines - <b>passwd</b> and <b>master.passwd</b> are copied to the remote machine as <b>/etc/passwd.new</b> and <b>/etc/master.passwd.new</b> and moved to <b>/etc/passwd</b> and <b>/etc/master.passwd</b> if no errors occur.
+ <li>nismachines - <b>passwd</b> and <b>shadow</b> are copied to the <b>/etc/global</b> directory on the remote machine. If no errors occur, the command <b>( cd /var/yp; make; )</b> is executed on the remote machine.
+ <li>erpcdmachines - <b>acp_passwd</b> and <b>acp_dialup</b> are copied to the <b>/usr/annex</b> directory on the remote machine. If no errors occur, the command <b>( kill -USR1 `cat /usr/annex/erpcd.pid` )</b> is executed on the remote machine.
+ <li>radiusmachines - <b>users</b> is copied to the <b>/etc/raddb</b> directory on the remote machine. If no errors occur, the command <b>( builddbm )</b> is executed on the remote machine.
</ul>
<li>site_perl/svc_acct.pm - If a shellmachine is defined, users can be created, modified and deleted remotely; see below.
<ul>
- <li>The command `useradd -d <i>homedir</i> -s <i>shell</i> -u <i>uid</i> <i>username</i>' is executed when a user is added.
- <li>The command `userdel <i>username</i>' is executed with a user is deleted.
- <li>If a user's home directory changes, the command `[ -d <i>old_homedir</i> &amp;&amp; ( chmod u+t <i>old_homedir</i>; umask 022; mkdir <i>new_homedir</i>; cd <i>old_homedir</i>; find . -depth -print | cpio -pdm <i>new_homedir</i>; chmod u-t <i>new_homedir</i>; chown -R <i>uid</i>.<i>gid</i> <i>new_homedir</i>; rm -rf <i>old_homedir</i> )' is executed.
+ <li>The command <b>useradd -d <i>homedir</i> -s <i>shell</i> -u <i>uid</i> <i>username</i></b> is executed when a user is added.
+ <li>The command <b>userdel <i>username</i></b> is executed with a user is deleted.
+ <li>If a user's home directory changes, the command <b>[ -d <i>old_homedir</i> &amp;&amp; ( chmod u+t <i>old_homedir</i>; umask 022; mkdir <i>new_homedir</i>; cd <i>old_homedir</i>; find . -depth -print | cpio -pdm <i>new_homedir</i>; chmod u-t <i>new_homedir</i>; chown -R <i>uid</i>.<i>gid</i> <i>new_homedir</i>; rm -rf <i>old_homedir</i> )</b> is executed.
</ul>
- <li>bin/svc_acct_sm.export will create <a href="http://www.qmail.org">Qmail</a> `rcpthosts', `recipientmap' and `virtualdomains' files and <a href="http://www.sendmail.org">Sendmail</a> `virtusertable' and `sendmail.cw' files in the `/var/spool/freeside/export' directory. Using the appropriate <a href="config.html">configuration files</a>, you can export these files to your remote machines unattemded; see below.
+ <li>bin/svc_acct_sm.export will create <a href="http://www.qmail.org">Qmail</a> <b>rcpthosts</b>, <b>recipientmap</b> and <b>virtualdomains</b> files and <a href="http://www.sendmail.org">Sendmail</a> <b>virtusertable</b> and <b>sendmail.cw</b> files in the <b>/usr/local/etc/freeside/export.<i>datasrc</i></b> directory. Using the appropriate <a href="config.html">configuration files</a>, you can export these files to your remote machines unattemded; see below.
<ul>
- <li>qmailmachines - recipientmap, virtualdomains and rcpthosts are copied to the `/var/qmail/control' directory on the remote machine. Note: If you <a href="legacy.html#svc_acct_sm">imported</a> qmail configuration files, run the generated `/var/spool/freeside/export/virtualdomains.FIX' on a machine with your user home directories before exporting qmail configuration files.
- <li>shellmachine - The command `[ -e <i>homedir</i>/.qmail-default ] || { touch <i>homedir</i>/.qmail-default; chown <i>uid</i>.<i>gid</i> <i>homedir</i>/.qmail-default; }' will be run on this machine for users in the virtualdomains file.
- <li>sendmailmachines - sendmail.cw and virtusertable are copied to the remote machine as /etc/sendmail.cw.new and /etc/virtusertable.new and moved to /etc/sendmail.cw and /etc/virtusertable if no errors occur.
+ <li>qmailmachines - <b>recipientmap</b>, <b>virtualdomains</b> and <b>rcpthosts</b> are copied to the <b>/var/qmail/control</b> directory on the remote machine. Note: If you <a href="legacy.html#svc_acct_sm">imported</a> qmail configuration files, run the generated <b>/usr/local/etc/freeside/export.<i>datasrc</i>/virtualdomains.FIX</b> on a machine with your user home directories before exporting qmail configuration files.
+ <li>shellmachine - The command <b>[ -e <i>homedir</i>/.qmail-default ] || { touch <i>homedir</i>/.qmail-default; chown <i>uid</i>.<i>gid</i> <i>homedir</i>/.qmail-default; }</b> will be run on this machine for users in the virtualdomains file.
+ <li>sendmailmachines - <b>sendmail.cw</b> and <b>virtusertable</b> are copied to the remote machine as <b>/etc/sendmail.cw.new</b> and <b>/etc/virtusertable.new</b> and moved to <b>/etc/sendmail.cw</b> and <b>/etc/virtusertable</b> if no errors occur.
</ul>
- <li>site_perl/svc_acct_sm.pm - If the qmailmachines configuration file exists and a shellmachine is defined, user `.qmail-' files can be updated.
+ <li>site_perl/svc_acct_sm.pm - If the qmailmachines configuration file exists and a shellmachine is defined, user <b>.qmail-</b> files can be updated.
<ul>
- <li>The command `[ -e <i>homedir</i>/.qmail-<i>domain</i>-default ] || { touch <i>homedir</i>/.qmail-<i>domain</i>-default; chown <i>uid</i>.<i>gid</i> <i>homedir</i>/.qmail-<i>domain</i>-default; }' is run.
+ <li>The command <b>[ -e <i>homedir</i>/.qmail-<i>domain</i>-default ] || { touch <i>homedir</i>/.qmail-<i>domain</i>-default; chown <i>uid</i>.<i>gid</i> <i>homedir</i>/.qmail-<i>domain</i>-default; }</b> is run.
</ul>
</ul>
<br><a name=ssh>Unattended remote login</a> - Freeside can login to remote machines unattended using SSH. This can pose a security risk if not configured correctly, and will allow an intruder who breaks into your freeside machine full access to your remote machines. <b>Do not use this feature unless you understand what you are doing!</b>
diff --git a/htdocs/docs/index.html b/htdocs/docs/index.html
index 20051ca4d..21ec25755 100644
--- a/htdocs/docs/index.html
+++ b/htdocs/docs/index.html
@@ -6,7 +6,10 @@
<ul>
<li><a href="install.html">New Installation</a>
<li><a href="upgrade.html">Upgrading from 1.0.x to 1.1.x</a>
- <li><a href="upgrade2.html">Upgrading from 1.1.x to 1.1.3</a>
+ <li><a href="upgrade2.html">Upgrading from 1.1.x to 1.1.4</a>
+ <li><a href="upgrade3.html">Upgrading from 1.1.x to 1.2.x</a>
+ <li><a href="upgrade4.html">Upgrading from 1.2.x to 1.2.2</a>
+ <li><a href="upgrade5.html">Upgrading from 1.2.2 to 1.3.0</a>
<li><a href="config.html">Configuration files</a>
<!--
<li><a href="admin.html">Administration</a>
@@ -15,9 +18,10 @@
<li><a href="legacy.html">Importing legacy data</a>
<li><a href="export.html">File exporting and remote setup</a>
<li><a href="passwd.html">fs_passwd</a>
+ <li><a href="signup.html">Signup server</a>
<li><a href="billing.html">Billing</a>
<li><a href="trouble.html">Troubleshooting</a>
<li><a href="schema.html">Schema reference</a>
- <li><a href="man/">Perl API</a>
+ <li><a href="man/FS.html">Perl API</a>
</ul>
</body>
diff --git a/htdocs/docs/install.html b/htdocs/docs/install.html
index c4784ebf6..574ab91e4 100644
--- a/htdocs/docs/install.html
+++ b/htdocs/docs/install.html
@@ -7,17 +7,21 @@ Before installing, you need:
<ul>
<li>A web server, such as <a href="http://www.apache-ssl.org">Apache-SSL</a> or <a href="http://www.apache.org">Apache</a>
<li><a href="ftp://ftp.cs.hut.fi/pub/ssh/">SSH</a>
- <li>agrep from the <a href="http://glimpse.cs.arizona.edu">Glimpse</a> distribution, if you want fuzzy searching capability
- <li><a href="http://www.perl.com/CPANl/doc/relinfo/INSTALL.html">Perl</a> (at least 5.004_04)
- <li>A database engine supported by Perl's <a href="http://www.hermetica.com/technologia/DBI/">DBI</a>, such as <a href="http://www.tcx.se/">MySQL</a> or <a href="http://www.postgresql.org/">PostgreSQL</a>
- <li>Perl modules
+ <li><a href="http://www.perl.com/CPAN/doc/relinfo/INSTALL.html">Perl</a> (at least 5.004_05 for the 5.004 series or 5.005_03 for the 5.005 series. Don't enable experimental features like threads or the PerlIO abstraction layer.)
+ <li>A database engine supported by Perl's <a href="http://www.hermetica.com/technologia/DBI/">DBI</a>, such as <a href="http://www.tcx.se/">MySQL</a> or <a href="http://www.postgresql.org/">PostgreSQL</a> (verstion 6.5 or higher) (see the <a href="postgresql.html">PostgreSQL notes</a>)
+ <li>Perl modules (<a href="http://www.perl.com/CPAN/doc/manual/html/lib/CPAN.html">CPAN</a> will query, download and build perl modules automatically)
<ul>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/Array/">Array-PrintCols</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/Term/">Term-Query</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/MIME/">MIME-Base64</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/Data">Data-Dumper</a>
- <li><a href="http://www.perl.com/CPAN/modules/by-module/MD5">MD5</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/MD5">Digest-MD5</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/URI">URI</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/HTTP">HTML-Parser</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/Net">libnet</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/Locale">Locale-Codes</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/Net">Net-Whois</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/LWP/">libwww-perl</a>
- <li><a href="http://www.perl.com/CPAN/modules/by-module/CGI/">CGI-modules</a> (<b>NOT</b> CGI.pm) with this <a href="CGI-modules-2.76-patch.txt">patch</a> applied
<li><a href="http://www.perl.com/CPAN/modules/by-module/Business/">Business-CreditCard</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/Data/">Data-ShowTable</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/Mail/">MailTools</a>
@@ -25,6 +29,7 @@ Before installing, you need:
<li><a href="http://www.perl.com/CPAN/modules/by-module/Date/">DateManip</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/File/">File-CounterFile</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/FreezeThaw/">FreezeThaw</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/String/">String-Approx</a>
<li><a href="http://www.perl.com/CPAN/modules/by-module/DBI/">DBI
<li><a href="http://www.perl.com/CPAN/modules/by-module/DBD/">DBD for your database engine</a>
</ul>
@@ -32,25 +37,38 @@ Before installing, you need:
Install the Freeside distribution:
<ul>
<li>Add the user `freeside' to your system.
- <li>Add the freeside database to your database engine. (with <a href="http://www.mysql.com/Manual_chapter/manual_Syntax.html#Create database">MySQL</a>) (with <a href="http://www.postgresql.org/docs/admin/manage-ag.htm#AEN854">PostgreSQL</a>)
- <li>Allow the freeside user full access to the freeside database. (with <a href="http://www.mysql.com/Manual_chapter/manual_Privilege_system.html#Privilege system">MySQL</a>) (with <a href="http://www.postgresql.org/docs/admin/newuser.htm">PostgreSQL</a>)
+ <li>Add the freeside database to your database engine. (with <a href="http://www.mysql.com/Manual_chapter/manual_Syntax.html#Create_database">MySQL</a>) (with <a href="http://www.postgresql.org/docs/admin/manage-ag.htm#AEN854">PostgreSQL</a>)
+ <li>Allow the freeside user full access to the freeside database. (with <a href="http://www.mysql.com/Manual_chapter/manual_Privilege_system.html#Privilege_system">MySQL</a>) (with <a href="http://www.postgresql.org/docs/admin/newuser.htm">PostgreSQL</a>)
<li>Unpack the tarball: <pre>gunzip -c fs-x.y.z.tar.gz | tar xvf -</pre>
- <li>Copy or link fs-x.y.z/site_perl to FS in your site_perl directory. (try `<code>perl -V</code>' if unsure) <pre>mkdir /usr/local/lib/site_perl/FS
-cp fs-x.y.z/site_perl/* /usr/local/lib/site_perl/FS</pre> or <pre>ln -s /full/path/to/fs-x.y.z/site_perl /usr/local/lib/site_perl/FS</pre>
+ <li>Build and install the Perl libraries:
+ <pre>
+$ cd FS/
+$ perl Makefile.PL
+$ make
+$ su
+# make install</pre>
<li>Copy or link fs-x.y.z/htdocs to your web server's document space. <pre>mkdir /usr/local/apache/htdocs/freeside
cp -r fs-x.y.z/htdocs/* /usr/local/apache/htdocs/freeside</pre> or <pre>ln -s /full/path/to/fs-x.y.z/htdocs /usr/local/apache/htdocs/freeside</pre>
<li>Restrict access to this web interface. (with <a href="http://www.apache.org/docs/misc/FAQ.html#user-authentication">Apache</a>)
<li>Enable CGI execution for files with the `.cgi' extension. (with <a href="http://www.apache.org/docs/mod/mod_mime.html#addhandler">Apache</a>)
- <li>Set ownership and permissions for the web interface. Your system should support secure setuid scripts or Perl's emulation, see <a href="http://www.perl.com/CPAN-local/doc/manual/html/pod/perlsec.html#Security_Bugs">perlsec: Security Bugs</a> for information and workarounds.
+ <li>Set ownership and permissions for the web interface. The web interface needs to run as the freeside user - there are several ways to do this.
+ <ul>
+ <li>Use Perl's setuid emulation: see the <a href="http://www.perl.com/CPAN-local/doc/manual/html/pod/perlsec.html#Security_Bugs">Security Bugs</a> section of the <a href="http://www.perl.com/CPAN-local/doc/manual/html/pod/perlsec.html">perlsec</a> manpage.
<pre>cd /usr/local/apache/htdocs/freeside
chown -R freeside .
chmod 4755 browse/*.cgi edit/*.cgi edit/process/*.cgi misc/*.cgi misc/process/*.cgi search/*.cgi view/*.cgi</pre>
-<li>Create the base Freeside directory `/var/spool/freeside', and the subdirectories `conf', `counters', and `export'. <pre>mkdir /var/spool/freeside
-mkdir /var/spool/freeside/conf
-mkdir /var/spool/freeside/counters
-mkdir /var/spool/freeside/export
-chown -R freeside /var/spool/freeside</pre>
- <li>Create the necessary <a href="config.html">configuration files</a>.
- <li>Run bin/fs-setup to create the database tables.
+ <li>Use Apache's <a href="http://www.apache.org/docs/suexec.html">suEXEC</a>.
+<pre>cd /usr/local/apache/htdocs/freeside
+chown -R freeside .
+chmod 755 browse/*.cgi edit/*.cgi edit/process/*.cgi misc/*.cgi misc/process/*.cgi search/*.cgi view/*.cgi</pre>
+ <li>Use <a href="http://perl.apache.org/">mod_perl</a>. You should run a separate iteration of Apache[-SSL] as the freeside user. (Warning: The redirect method of CGI.pm 2.36 [as distributed with Perl 5.004_04] is broken under mod_perl. Downlaod the current version from <a href="http://www.perl.com/CPAN/modules/by-module/CGI">CPAN</a>. Apache 1.3.6 is also highly recommended because of signal handling problems in earlier versions.)
+<pre>cd /usr/local/apache/htdocs/freeside
+chown -R root .
+chmod 755 browse/*.cgi edit/*.cgi edit/process/*.cgi misc/*.cgi misc/process/*.cgi search/*.cgi view/*.cgi</pre>
+ </ul>
+<li>Create the necessary <a href="config.html">configuration files</a>.
+<li>Create the `/usr/local/etc/freeside/counters.<i>datasrc</i>', and
+ `/usr/local/etc/freeside/export.<i>datasrc</i>' directories for each <i>datasrc</i> (owned by the freeside user).
+ <li>As the freeside user, run bin/fs-setup to create the database tables.
</ul>
</body>
diff --git a/htdocs/docs/legacy.html b/htdocs/docs/legacy.html
index 40e09cb3c..3ab21dab2 100644
--- a/htdocs/docs/legacy.html
+++ b/htdocs/docs/legacy.html
@@ -4,7 +4,7 @@
<body>
<h1>Importing legacy data</h1>
<ul>
- <li><a name="svc_acct">bin/svc_acct.import</a> - Import `passwd', ( `shadow' or `master.passwd' ) and RADIUS `users'. Before running bin/svc_acct.import, you need <a href="http://rootwood.sisd.com/freeside/browse/part_svc.cgi">services</a> (with table svc_acct) as follows:
+ <li><a name="svc_acct">bin/svc_acct.import</a> - Import `passwd', ( `shadow' or `master.passwd' ) and RADIUS `users'. Before running bin/svc_acct.import, you need <a href="../browse/part_svc.cgi">services</a> (with table svc_acct) as follows:
<ul>
<li>Most accounts probably have entries in passwd and users (with Port-Limit nonexistant or 1)
<li>Some accounts have entries in passwd and users, but with Port-Limit 2 (or more)
@@ -13,7 +13,7 @@
<li>POP mail accounts have entries in passwd only, and have a particular shell.
<li>Everything else in passwd is a shell account.
</ul>
- <li><a name="svc_acct_sm">bin/svc_acct_sm.import</a> - Import qmail ( `virtualdomains' and `rcpthosts' ), or sendmail ( `virtusertable' and `sendmail.cw' ) files. Before running bin/svc_acct_sm.import, you need <a href="http://rootwood.sisd.com/freeside/browse/part_svc.cgi">services</a> as follows:
+ <li><a name="svc_acct_sm">bin/svc_acct_sm.import</a> - Import qmail ( `virtualdomains' and `rcpthosts' ), or sendmail ( `virtusertable' and `sendmail.cw' ) files. Before running bin/svc_acct_sm.import, you need <a href="../browse/part_svc.cgi">services</a> as follows:
<ul>
<li>Domain (table svc_acct)
<li>Mail alias (table svc_acct_sm)
diff --git a/htdocs/docs/man/Bill.txt b/htdocs/docs/man/Bill.txt
deleted file mode 100644
index 545dd1a4c..000000000
--- a/htdocs/docs/man/Bill.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-NAME
- FS::Bill - Legacy stub
-
-SYNOPSIS
- The functionality of FS::Bill has been integrated into
- FS::cust_main.
-
-HISTORY
- ivan@voicenet.com 97-jul-24 - 25 - 28
-
- use Safe; evaluate all fees with perl (still on TODO list until
- I write some examples & test opmask to see if we can read db)
- %hash=$obj->hash later ivan@sisd.com 98-mar-13
-
- packages with no next bill date start at $time not time, this
- should eliminate the last of the problems with billing at a past
- date also rewrite the invoice priting logic not to print
- invoices for things that haven't happended yet and update
- $cust_bill->printed when we print so PAST DUE notices work, and
- s/date/_date/ ivan@sisd.com 98-jun-4
-
- more logic for past due stuff - packages with no next bill date
- start at $cust_pkg->setup || $time ivan@sisd.com 98-jul-13
-
- moved a few things in collection logic; negative charges should
- work ivan@sisd.com 98-aug-6
-
- pod, moved everything to FS::cust_main ivan@sisd.com 98-sep-19
-
diff --git a/htdocs/docs/man/CGI.txt b/htdocs/docs/man/CGI.txt
deleted file mode 100644
index 54f9b8a6a..000000000
--- a/htdocs/docs/man/CGI.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-NAME
- FS::CGI - Subroutines for the web interface
-
-SYNOPSIS
- use FS::CGI qw(header menubar idiot eidiot);
-
- print header( 'Title', '' );
- print header( 'Title', menubar('item', 'URL', ... ) );
-
- idiot "error message";
- eidiot "error message";
-
-DESCRIPTION
- Provides a few common subroutines for the web interface.
-
-SUBROUTINES
- header TITLE, MENUBAR
- Returns an HTML header.
-
- menubar ITEM, URL, ...
- Returns an HTML menubar.
-
- idiot ERROR
- Sends headers and an HTML error message.
-
- eidiot ERROR
- Sends headers and an HTML error message, then exits.
-
-BUGS
- Not OO.
-
- Not complete.
-
- Uses CGI-modules instead of CGI.pm
-
-SEE ALSO
- the CGI::Base manpage
-
-HISTORY
- subroutines for the HTML/CGI GUI, not properly OO. :(
-
- ivan@sisd.com 98-apr-16 ivan@sisd.com 98-jun-22
-
- lose the background, eidiot ivan@sisd.com 98-sep-2
-
- pod ivan@sisd.com 98-sep-12
-
diff --git a/htdocs/docs/man/Conf.txt b/htdocs/docs/man/Conf.txt
deleted file mode 100644
index c46c9ee6a..000000000
--- a/htdocs/docs/man/Conf.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-NAME
- FS::Conf - Read access to Freeside configuration values
-
-SYNOPSIS
- use FS::Conf;
-
- $conf = new FS::Conf;
- $conf = new FS::Conf "/non/standard/config/directory";
-
- $dir = $conf->dir;
-
- $value = $conf->config('key');
- @list = $conf->config('key');
- $bool = $conf->exists('key');
-
-DESCRIPTION
- Read access to Freeside configuration values. Keys currently map
- to filenames, but this may change in the future.
-
-METHODS
- new [ DIRECTORY ]
- Create a new configuration object. Optionally, a non-default
- directory may be specified.
-
- dir Returns the directory.
-
- config
- Returns the configuration value or values (depending on
- context) for key.
-
- exists
- Returns true if the specified key exists, even if the
- corresponding value is undefined.
-
-BUGS
- The option to specify a non-default directory should probably be
- removed.
-
- Write access (with locking) should be implemented.
-
-SEE ALSO
- config.html from the base documentation contains a list of
- configuration files.
-
-HISTORY
- Ivan Kohler <ivan@sisd.com> 98-sep-6
-
diff --git a/htdocs/docs/man/FS.html b/htdocs/docs/man/FS.html
new file mode 100644
index 000000000..b2f0dd3a2
--- /dev/null
+++ b/htdocs/docs/man/FS.html
@@ -0,0 +1,247 @@
+<HTML>
+<HEAD>
+<TITLE>FS - Freeside Perl modules</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <UL>
+
+ <LI><A HREF="#Database_metadata_classes">Database metadata classes</A>
+ <LI><A HREF="#Utility_classes">Utility classes</A>
+ <LI><A HREF="#Database_record_classes">Database record classes</A>
+ <LI><A HREF="#User_Interface_classes_under_de">User Interface classes (under development; not yet usable)</A>
+ <LI><A HREF="#Notes">Notes</A>
+ </UL>
+
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#SUPPORT">SUPPORT</A>
+ <LI><A HREF="#AUTHOR">AUTHOR</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS - Freeside Perl modules
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+FS is the temporary prefix for many disparate modules written for the
+Freeside ISP billing software. This includes:
+
+<P>
+<HR>
+<H2><A NAME="Database_metadata_classes">Database metadata classes</A></H2>
+<P>
+<A HREF="./FS/dbdef.html">FS::dbdef</A> - Database class
+
+<P>
+<A HREF="./FS/dbdef_table.html">FS::dbdef_table</A> - Database table class
+
+<P>
+<A HREF="./FS/dbdef_column.html">FS::dbdef_column</A> - Database column class
+
+<P>
+<A HREF="./FS/dbdef_colgroup.html">FS::dbdef_colgroup</A> - Database column group class
+
+<P>
+<A HREF="./FS/dbdef_index.html">FS::dbdef_index</A> - Database index class
+
+<P>
+<A HREF="./FS/dbdef_unique.html">FS::dbdef_unique</A> - Database unique index class
+
+<P>
+<HR>
+<H2><A NAME="Utility_classes">Utility classes</A></H2>
+<P>
+<A HREF="./FS/SSH.html">FS::SSH</A> - Simple wrappers around ssh and scp commands.
+
+<P>
+<A HREF="./FS/Conf.html">FS::Conf</A> - Freeside configuration values
+
+<P>
+<A HREF="./FS/UID.html">FS::UID</A> - User class (not yet OO)
+
+<P>
+<A HREF="./FS/CGI.html">FS::CGI</A> - Non OO-subroutines for the web interface. This is depriciated. Future
+development will be focused on the FS::UI user-interface classes (see
+below).
+
+<P>
+<HR>
+<H2><A NAME="Database_record_classes">Database record classes</A></H2>
+<P>
+<A HREF="./FS/Record.html">FS::Record</A> - Database record base class
+
+<P>
+<A HREF="./FS/svc_acct_pop.html">FS::svc_acct_pop</A> - POP (Point of Presence, not Post Office Protocol) class
+
+<P>
+<A HREF="./FS/part_referral.html">FS::part_referral</A> - Referral class
+
+<P>
+<A HREF="./FS/cust_main_county.html">FS::cust_main_county</A> - Locale (tax rate) class
+
+<P>
+<A HREF="./FS/svc_Common.html">FS::svc_Common</A> - Service base class
+
+<P>
+<A HREF="./FS/svc_acct.html">FS::svc_acct</A> - Account (shell, RADIUS, POP3) class
+
+<P>
+<A HREF="./FS/svc_domain.html">FS::svc_domain</A> - Domain class
+
+<P>
+<A HREF="./FS/svc_acct_sm.html">FS::svc_acct_sm</A> - Vitual mail alias class
+
+<P>
+<A HREF="./FS/part_svc.html">FS::part_svc</A> - Service definition class
+
+<P>
+<A HREF="./FS/part_pkg.html">FS::part_pkg</A> - Package (billing item) definition class
+
+<P>
+<A HREF="./FS/pkg_svc.html">FS::pkg_svc</A> - Class linking package (billing item) definitions (see <A HREF="./FS/part_pkg.html">FS::part_pkg</A>) with service definitions (see <A HREF="./FS/part_svc.html">FS::part_svc</A>)
+
+<P>
+<A HREF="./FS/agent.html">FS::agent</A> - Agent (reseller) class
+
+<P>
+<A HREF="./FS/agent_type.html">FS::agent_type</A> - Agent type class
+
+<P>
+<A HREF="./FS/type_pkgs.html">FS::type_pkgs</A> - Class linking agent types (see
+<A HREF="./FS/agent_type.html">FS::agent_type</A>) with package (billing item) definitions (see <A HREF="./FS/part_pkg.html">FS::part_pkg</A>)
+
+<P>
+<A HREF="./FS/cust_svc.html">FS::cust_svc</A> - Service class
+
+<P>
+<A HREF="./FS/cust_pkg.html">FS::cust_pkg</A> - Package (billing item) class
+
+<P>
+<A HREF="./FS/cust_main.html">FS::cust_main</A> - Customer class
+
+<P>
+<A HREF="./FS/cust_main_invoice.html">FS::cust_main_invoice</A> - Invoice destination class
+
+<P>
+<A HREF="./FS/cust_bill.html">FS::cust_bill</A> - Invoice class
+
+<P>
+<A HREF="./FS/cust_bill_pkg.html">FS::cust_bill_pkg</A> - Invoice line item class
+
+<P>
+<A HREF="./FS/cust_pay.html">FS::cust_pay</A> - Payment class
+
+<P>
+<A HREF="./FS/cust_credit.html">FS::cust_credit</A> - Credit class
+
+<P>
+<A HREF="./FS/cust_refund.html">FS::cust_refund</A> - Refund class
+
+<P>
+<A HREF="./FS/cust_pay_batch.html">FS::cust_pay_batch</A> - Credit card transaction queue class
+
+<P>
+<HR>
+<H2><A NAME="User_Interface_classes_under_de">User Interface classes (under development; not yet usable)</A></H2>
+<P>
+<A HREF="./FS/UI/Base.html">FS::UI::Base</A> - User-interface base class
+
+<P>
+<A HREF="./FS/UI/Gtk.html">FS::UI::Gtk</A> - Gtk user-interface class
+
+<P>
+<A HREF="./FS/UI/CGI.html">FS::UI::CGI</A> - CGI (HTML) user-interface class
+
+<P>
+<A HREF="./FS/UI/agent.html">FS::UI::agent</A> - agent table user-interface class
+
+<P>
+<HR>
+<H2><A NAME="Notes">Notes</A></H2>
+<P>
+To quote <CODE>perl(1),</CODE> ``If you're intending to read these straight
+through for the first time, the suggested order will tend to reduce the
+number of forward references.''
+
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+Freeside is a billing and administration package for Internet Service
+Providers.
+
+<P>
+The Freeside home page is at &lt;http://www.sisd.com/freeside&gt;.
+
+<P>
+The main documentation is in htdocs/docs.
+
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: FS.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="SUPPORT">SUPPORT</A></H1>
+<P>
+A mailing list for users and developers is available. Send a blank message
+to &lt;<A
+HREF="mailto:ivan-freeside-subscribe@sisd.com">ivan-freeside-subscribe@sisd.com</A>&gt;
+to subscribe.
+
+<P>
+Commercial support is available; see
+&lt;http://www.sisd.com/freeside/commercial.html&gt;.
+
+<P>
+<HR>
+<H1><A NAME="AUTHOR">AUTHOR</A></H1>
+<P>
+Primarily Ivan Kohler &lt;<A
+HREF="mailto:ivan@sisd.com">ivan@sisd.com</A>&gt;, with help from many kind
+folks.
+
+<P>
+See the CREDITS file in the Freeside distribution for a (hopefully)
+complete list and the individal files for details.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<CODE>perl(1),</CODE> main Freeside documentation in htdocs/docs/
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The version number of the FS Perl extension differs from the version of the
+Freeside distribution, which are both different from the CVS version tag
+for each file, which appears under the VERSION heading.
+
+<P>
+Those modules which would be useful separately should be pulled out,
+renamed appropriately and uploaded to CPAN.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/Bill.html b/htdocs/docs/man/FS/Bill.html
new file mode 100644
index 000000000..e5832f8d9
--- /dev/null
+++ b/htdocs/docs/man/FS/Bill.html
@@ -0,0 +1,32 @@
+<HTML>
+<HEAD>
+<TITLE>FS::Bill - Legacy stub</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::Bill - Legacy stub
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+The functionality of FS::Bill has been integrated into FS::cust_main.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/CGI.html b/htdocs/docs/man/FS/CGI.html
new file mode 100644
index 000000000..e1a42ec59
--- /dev/null
+++ b/htdocs/docs/man/FS/CGI.html
@@ -0,0 +1,115 @@
+<HTML>
+<HEAD>
+<TITLE>FS::CGI - Subroutines for the web interface</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#SUBROUTINES">SUBROUTINES</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::CGI - Subroutines for the web interface
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::CGI qw(header menubar idiot eidiot popurl);
+</PRE>
+<P>
+<PRE> print header( 'Title', '' );
+ print header( 'Title', menubar('item', 'URL', ... ) );
+</PRE>
+<P>
+<PRE> idiot &quot;error message&quot;;
+ eidiot &quot;error message&quot;;
+</PRE>
+<P>
+<PRE> $url = popurl; #returns current url
+ $url = popurl(3); #three levels up
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+Provides a few common subroutines for the web interface.
+
+<P>
+<HR>
+<H1><A NAME="SUBROUTINES">SUBROUTINES</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_header">header TITLE, MENUBAR</A></STRONG><DD>
+<P>
+Returns an HTML header.
+
+<DT><STRONG><A NAME="item_menubar">menubar ITEM, URL, ...</A></STRONG><DD>
+<P>
+Returns an HTML menubar.
+
+<DT><STRONG><A NAME="item_idiot">idiot ERROR</A></STRONG><DD>
+<P>
+This is depriciated. Don't use it.
+
+<P>
+Sends headers and an HTML error message.
+
+<DT><STRONG><A NAME="item_eidiot">eidiot ERROR</A></STRONG><DD>
+<P>
+This is depriciated. Don't use it.
+
+<P>
+Sends headers and an HTML error message, then exits.
+
+<DT><STRONG><A NAME="item_popurl">popurl LEVEL</A></STRONG><DD>
+<P>
+Returns current URL with LEVEL levels of path removed from the end (default
+0).
+
+<DT><STRONG><A NAME="item_table">table</A></STRONG><DD>
+<P>
+Returns HTML tag for beginning a table.
+
+<DT><STRONG><A NAME="item_itable">itable</A></STRONG><DD>
+<P>
+Returns HTML tag for beginning an (invisible) table.
+
+<DT><STRONG><A NAME="item_ntable">ntable</A></STRONG><DD>
+<P>
+This is getting silly.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Not OO.
+
+<P>
+Not complete.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF=".././FS/CGI.html#">the CGI manpage</A>, <A HREF="../CGI/Base.html">CGI::Base</A>
+
+
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/Conf.html b/htdocs/docs/man/FS/Conf.html
new file mode 100644
index 000000000..e4555c3a9
--- /dev/null
+++ b/htdocs/docs/man/FS/Conf.html
@@ -0,0 +1,94 @@
+<HTML>
+<HEAD>
+<TITLE>FS::Conf - Read access to Freeside configuration values</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::Conf - Read access to Freeside configuration values
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::Conf;
+</PRE>
+<P>
+<PRE> $conf = new FS::Conf &quot;/config/directory&quot;;
+</PRE>
+<P>
+<PRE> $FS::Conf::default_dir = &quot;/config/directory&quot;;
+ $conf = new FS::Conf;
+</PRE>
+<P>
+<PRE> $dir = $conf-&gt;dir;
+</PRE>
+<P>
+<PRE> $value = $conf-&gt;config('key');
+ @list = $conf-&gt;config('key');
+ $bool = $conf-&gt;exists('key');
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+Read access to Freeside configuration values. Keys currently map to
+filenames, but this may change in the future.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new [ DIRECTORY ]</A></STRONG><DD>
+<P>
+Create a new configuration object. A directory arguement is required if
+$FS::Conf::default_dir has not been set.
+
+<DT><STRONG><A NAME="item_dir">dir</A></STRONG><DD>
+<P>
+Returns the directory.
+
+<DT><STRONG><A NAME="item_config">config</A></STRONG><DD>
+<P>
+Returns the configuration value or values (depending on context) for key.
+
+<DT><STRONG><A NAME="item_exists">exists</A></STRONG><DD>
+<P>
+Returns true if the specified key exists, even if the corresponding value
+is undefined.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Write access (with locking) should be implemented.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+config.html from the base documentation contains a list of configuration
+files.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/Invoice.html b/htdocs/docs/man/FS/Invoice.html
new file mode 100644
index 000000000..283e89a35
--- /dev/null
+++ b/htdocs/docs/man/FS/Invoice.html
@@ -0,0 +1,32 @@
+<HTML>
+<HEAD>
+<TITLE>FS::Invoice - Legacy stub</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::Invoice - Legacy stub
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+The functionality of FS::Invoice has been integrated in FS::cust_bill.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/Record.html b/htdocs/docs/man/FS/Record.html
new file mode 100644
index 000000000..da1fc5287
--- /dev/null
+++ b/htdocs/docs/man/FS/Record.html
@@ -0,0 +1,380 @@
+<HTML>
+<HEAD>
+<TITLE>FS::Record - Database record objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#CONSTRUCTORS">CONSTRUCTORS</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#SUBROUTINES">SUBROUTINES</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::Record - Database record objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::Record;
+ use FS::Record qw(dbh fields qsearch qsearchs dbdef);
+</PRE>
+<P>
+<PRE> $record = new FS::Record 'table', \%hash;
+ $record = new FS::Record 'table', { 'column' =&gt; 'value', ... };
+</PRE>
+<P>
+<PRE> $record = qsearchs FS::Record 'table', \%hash;
+ $record = qsearchs FS::Record 'table', { 'column' =&gt; 'value', ... };
+ @records = qsearch FS::Record 'table', \%hash;
+ @records = qsearch FS::Record 'table', { 'column' =&gt; 'value', ... };
+</PRE>
+<P>
+<PRE> $table = $record-&gt;table;
+ $dbdef_table = $record-&gt;dbdef_table;
+</PRE>
+<P>
+<PRE> $value = $record-&gt;get('column');
+ $value = $record-&gt;getfield('column');
+ $value = $record-&gt;column;
+</PRE>
+<P>
+<PRE> $record-&gt;set( 'column' =&gt; 'value' );
+ $record-&gt;setfield( 'column' =&gt; 'value' );
+ $record-&gt;column('value');
+</PRE>
+<P>
+<PRE> %hash = $record-&gt;hash;
+</PRE>
+<P>
+<PRE> $hashref = $record-&gt;hashref;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+ #$error = $record-&gt;add; #depriciated
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+ #$error = $record-&gt;del; #depriciated
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+ #$error = $new_record-&gt;rep($old_record); #depriciated
+</PRE>
+<P>
+<PRE> $value = $record-&gt;unique('column');
+</PRE>
+<P>
+<PRE> $value = $record-&gt;ut_float('column');
+ $value = $record-&gt;ut_number('column');
+ $value = $record-&gt;ut_numbern('column');
+ $value = $record-&gt;ut_money('column');
+ $value = $record-&gt;ut_text('column');
+ $value = $record-&gt;ut_textn('column');
+ $value = $record-&gt;ut_alpha('column');
+ $value = $record-&gt;ut_alphan('column');
+ $value = $record-&gt;ut_phonen('column');
+ $value = $record-&gt;ut_anythingn('column');
+</PRE>
+<P>
+<PRE> $dbdef = reload_dbdef;
+ $dbdef = reload_dbdef &quot;/non/standard/filename&quot;;
+ $dbdef = dbdef;
+</PRE>
+<P>
+<PRE> $quoted_value = _quote($value,'table','field');
+</PRE>
+<P>
+<PRE> #depriciated
+ $fields = hfields('table');
+ if ( $fields-&gt;{Field} ) { # etc.
+</PRE>
+<P>
+<PRE> @fields = fields 'table'; #as a subroutine
+ @fields = $record-&gt;fields; #as a method call
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+(Mostly) object-oriented interface to database records. Records are
+currently implemented on top of DBI. FS::Record is intended as a base class
+for table-specific classes to inherit from, i.e. FS::cust_main.
+
+<P>
+<HR>
+<H1><A NAME="CONSTRUCTORS">CONSTRUCTORS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new [ TABLE, ] HASHREF</A></STRONG><DD>
+<P>
+Creates a new record. It doesn't store it in the database, though. See
+<A HREF="#insert">insert</A> for that.
+
+<P>
+Note that the object stores this hash reference, not a distinct copy of the
+hash it points to. You can ask the object for a copy with the <EM>hash</EM>
+method.
+
+<P>
+TABLE can only be omitted when a dervived class overrides the table method.
+
+<DT><STRONG><A NAME="item_qsearch">qsearch TABLE, HASHREF</A></STRONG><DD>
+<P>
+Searches the database for all records matching (at least) the key/value
+pairs in HASHREF. Returns all the records found as `FS::TABLE' objects if
+that module is loaded (i.e. via `use FS::cust_main;'), otherwise returns
+FS::Record objects.
+
+<DT><STRONG><A NAME="item_qsearchs">qsearchs TABLE, HASHREF</A></STRONG><DD>
+<P>
+Same as qsearch, except that if more than one record matches, it <STRONG>carp</STRONG>s but returns the first. If this happens, you either made a logic error in
+asking for a single item, or your data is corrupted.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_table">table</A></STRONG><DD>
+<P>
+Returns the table name.
+
+<DT><STRONG><A NAME="item_dbdef_table">dbdef_table</A></STRONG><DD>
+<P>
+Returns the FS::dbdef_table object for the table.
+
+<DT><STRONG><A NAME="item_get">get, getfield COLUMN</A></STRONG><DD>
+<P>
+Returns the value of the column/field/key COLUMN.
+
+<DT><STRONG><A NAME="item_set">set, setfield COLUMN, VALUE</A></STRONG><DD>
+<P>
+Sets the value of the column/field/key COLUMN to VALUE. Returns VALUE.
+
+<DT><STRONG><A NAME="item_AUTLOADED">AUTLOADED METHODS</A></STRONG><DD>
+<P>
+$record-&gt;column is a synonym for $record-&gt;get('column');
+
+<P>
+$record-&gt;column('value') is a synonym for
+$record-&gt;set('column','value');
+
+<DT><STRONG><A NAME="item_hash">hash</A></STRONG><DD>
+<P>
+Returns a list of the column/value pairs, usually for assigning to a new
+hash.
+
+<P>
+To make a distinct duplicate of an FS::Record object, you can do:
+
+<P>
+<PRE> $new = new FS::Record ( $old-&gt;table, { $old-&gt;hash } );
+</PRE>
+<DT><STRONG><A NAME="item_hashref">hashref</A></STRONG><DD>
+<P>
+Returns a reference to the column/value hash.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Inserts this record to the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_add">add</A></STRONG><DD>
+<P>
+Depriciated (use insert instead).
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Delete this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_del">del</A></STRONG><DD>
+<P>
+Depriciated (use delete instead).
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replace the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_rep">rep</A></STRONG><DD>
+<P>
+Depriciated (use replace instead).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Not yet implemented, croaks. Derived classes should provide a check method.
+
+<DT><STRONG><A NAME="item_unique">unique COLUMN</A></STRONG><DD>
+<P>
+Replaces COLUMN in record with a unique number. Called by the <STRONG>add</STRONG> method on primary keys and single-field unique columns (see <A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>). Returns the new value.
+
+<DT><STRONG><A NAME="item_ut_float">ut_float COLUMN</A></STRONG><DD>
+<P>
+Check/untaint floating point numeric data: 1.1, 1, 1.1e10, 1e10. May not be
+null. If there is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_ut_number">ut_number COLUMN</A></STRONG><DD>
+<P>
+Check/untaint simple numeric data (whole numbers). May not be null. If
+there is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_ut_numbern">ut_numbern COLUMN</A></STRONG><DD>
+<P>
+Check/untaint simple numeric data (whole numbers). May be null. If there is
+an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_ut_money">ut_money COLUMN</A></STRONG><DD>
+<P>
+Check/untaint monetary numbers. May be negative. Set to 0 if null. If there
+is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_ut_text">ut_text COLUMN</A></STRONG><DD>
+<P>
+Check/untaint text. Alphanumerics, spaces, and the following punctuation
+symbols are currently permitted: ! @ # $ % &amp; ( ) - + ; : ' `` , . ? /
+May not be null. If there is an error, returns the error, otherwise returns
+false.
+
+<DT><STRONG><A NAME="item_ut_textn">ut_textn COLUMN</A></STRONG><DD>
+<P>
+Check/untaint text. Alphanumerics, spaces, and the following punctuation
+symbols are currently permitted: ! @ # $ % &amp; ( ) - + ; : ' `` , . ? /
+May be null. If there is an error, returns the error, otherwise returns
+false.
+
+<DT><STRONG><A NAME="item_ut_alpha">ut_alpha COLUMN</A></STRONG><DD>
+<P>
+Check/untaint alphanumeric strings (no spaces). May not be null. If there
+is an error, returns the error, otherwise returns false.
+
+<DT><STRONG>ut_alpha COLUMN</STRONG><DD>
+<P>
+Check/untaint alphanumeric strings (no spaces). May be null. If there is an
+error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_ut_phonen">ut_phonen COLUMN</A></STRONG><DD>
+<P>
+Check/untaint phone numbers. May be null. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_ut_anything">ut_anything COLUMN</A></STRONG><DD>
+<P>
+Untaints arbitrary data. Be careful.
+
+<DT><STRONG><A NAME="item_fields">fields [ TABLE ]</A></STRONG><DD>
+<P>
+This can be used as both a subroutine and a method call. It returns a list
+of the columns in this record's table, or an explicitly specified table.
+(See <A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>).
+
+<H1><A NAME="SUBROUTINES">SUBROUTINES</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_reload_dbdef">reload_dbdef([FILENAME])</A></STRONG><DD>
+<P>
+Load a database definition (see <A HREF="../FS/dbdef.html">FS::dbdef</A>), optionally from a non-default filename. This command is executed at
+startup unless
+<EM>$FS::Record::setup_hack</EM> is true. Returns a FS::dbdef object.
+
+<DT><STRONG><A NAME="item_dbdef">dbdef</A></STRONG><DD>
+<P>
+Returns the current database definition. See <A HREF="../FS/dbdef.html">FS::dbdef</A>.
+
+<DT><STRONG><A NAME="item__quote">_quote VALUE, TABLE, COLUMN</A></STRONG><DD>
+<P>
+This is an internal function used to construct SQL statements. It returns
+VALUE DBI-quoted (see <EM>DBI</EM>) unless VALUE is a number and the column type (see <A HREF="../FS/dbdef_column.html">FS::dbdef_column</A>) does not end in `char' or `binary'.
+
+<DT><STRONG><A NAME="item_hfields">hfields TABLE</A></STRONG><DD>
+<P>
+This is depriciated. Don't use it.
+
+<P>
+It returns a hash-type list with the fields of this record's table set
+true.
+
+</DL>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: Record.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+This module should probably be renamed, since much of the functionality is
+of general use. It is not completely unlike Adapter::DBI (see below).
+
+<P>
+Exported qsearch and qsearchs should be depriciated in favor of method
+calls (against an FS::Record object like the old search and searchs that
+qsearch and qsearchs were on top of.)
+
+<P>
+The whole fields / hfields mess should be removed.
+
+<P>
+The various WHERE clauses should be subroutined.
+
+<P>
+table string should be depriciated in favor of FS::dbdef_table.
+
+<P>
+No doubt we could benefit from a Tied hash. Documenting how exists /
+defined true maps to the database (and WHERE clauses) would also help.
+
+<P>
+The ut_ methods should ask the dbdef for a default length.
+
+<P>
+ut_sqltype (like ut_varchar) should all be defined
+
+<P>
+A fallback check method should be provided whith uses the dbdef.
+
+<P>
+The ut_money method assumes money has two decimal digits.
+
+<P>
+The Pg money kludge in the new method only strips `$'.
+
+<P>
+The ut_phonen method assumes US-style phone numbers.
+
+<P>
+The _quote function should probably use ut_float instead of a regex.
+
+<P>
+All the subroutines probably should be methods, here or elsewhere.
+
+<P>
+Probably should borrow/use some dbdef methods where appropriate (like sub
+fields)
+
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/dbdef.html">FS::dbdef</A>, <A HREF="../FS/UID.html">FS::UID</A>, <EM>DBI</EM>
+
+
+
+<P>
+Adapter::DBI from Ch. 11 of Advanced Perl Programming by Sriram Srinivasan.
+
+</DL>
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/SSH.html b/htdocs/docs/man/FS/SSH.html
new file mode 100644
index 000000000..aa8929b09
--- /dev/null
+++ b/htdocs/docs/man/FS/SSH.html
@@ -0,0 +1,104 @@
+<HTML>
+<HEAD>
+<TITLE>FS::SSH - Subroutines to call ssh and scp</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#SUBROUTINES">SUBROUTINES</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::SSH - Subroutines to call ssh and scp
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::SSH qw(ssh scp issh iscp sshopen2 sshopen3);
+</PRE>
+<P>
+<PRE> ssh($host, $command);
+</PRE>
+<P>
+<PRE> issh($host, $command);
+</PRE>
+<P>
+<PRE> scp($source, $destination);
+</PRE>
+<P>
+<PRE> iscp($source, $destination);
+</PRE>
+<P>
+<PRE> sshopen2($host, $reader, $writer, $command);
+</PRE>
+<P>
+<PRE> sshopen3($host, $reader, $writer, $error, $command);
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+<PRE> Simple wrappers around ssh and scp commands.
+</PRE>
+<P>
+<HR>
+<H1><A NAME="SUBROUTINES">SUBROUTINES</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_ssh">ssh HOST, COMMAND</A></STRONG><DD>
+<P>
+Calls ssh in batch mode.
+
+<DT><STRONG><A NAME="item_issh">issh HOST, COMMAND</A></STRONG><DD>
+<P>
+Prints the ssh command to be executed, waits for the user to confirm, and
+(optionally) executes the command.
+
+<DT><STRONG><A NAME="item_scp">scp SOURCE, DESTINATION</A></STRONG><DD>
+<P>
+Calls scp in batch mode.
+
+<DT><STRONG><A NAME="item_iscp">iscp SOURCE, DESTINATION</A></STRONG><DD>
+<P>
+Prints the scp command to be executed, waits for the user to confirm, and
+(optionally) executes the command.
+
+<DT><STRONG><A NAME="item_sshopen2">sshopen2 HOST, READER, WRITER, COMMAND</A></STRONG><DD>
+<P>
+Connects the supplied filehandles to the ssh process (in batch mode).
+
+<DT><STRONG><A NAME="item_sshopen3">sshopen3 HOST, WRITER, READER, ERROR, COMMAND</A></STRONG><DD>
+<P>
+Connects the supplied filehandles to the ssh process (in batch mode).
+
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Not OO.
+
+<P>
+scp stuff should transparantly use rsync-over-ssh instead.
+
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<EM>ssh</EM>, <EM>scp</EM>, <A HREF="../IPC/Open2.html">IPC::Open2</A>, <A HREF="../IPC/Open3.html">IPC::Open3</A>
+
+
+
+</DL>
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/UI/Base.html b/htdocs/docs/man/FS/UI/Base.html
new file mode 100644
index 000000000..91a4df64d
--- /dev/null
+++ b/htdocs/docs/man/FS/UI/Base.html
@@ -0,0 +1,117 @@
+<HTML>
+<HEAD>
+<TITLE>FS::UI::Base - Base class for all user-interface objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+ <LI><A HREF="#HISTORY">HISTORY</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::UI::Base - Base class for all user-interface objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::UI::SomeInterface;
+ use FS::UI::some_table;
+</PRE>
+<P>
+<PRE> $interface = new FS::UI::some_table;
+</PRE>
+<P>
+<PRE> $error = $interface-&gt;browse;
+ $error = $interface-&gt;search;
+ $error = $interface-&gt;view;
+ $error = $interface-&gt;edit;
+ $error = $interface-&gt;process;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::UI::Base object represents a user interface object. FS::UI::Base is
+intended as a base class for table-specfic classes to inherit from, i.e.
+FS::UI::cust_main. The simplest case, which will provide a default UI for
+your new table, is as follows:
+
+<P>
+<PRE> package FS::UI::table_name;
+ use vars qw ( @ISA );
+ use FS::UI::Base;
+ @ISA = qw( FS::UI::Base );
+ sub db_table { 'table_name'; }
+</PRE>
+<P>
+Currently available interfaces are: FS::UI::Gtk, an X-Windows UI
+implemented using the Gtk+ toolkit FS::UI::CGI, a web interface implemented
+using CGI.pm, etc.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new</A></STRONG><DD>
+<DT><STRONG><A NAME="item_browse">browse</A></STRONG><DD>
+<DT><STRONG><A NAME="item_title">title</A></STRONG><DD>
+<DT><STRONG><A NAME="item_addwidget">addwidget</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: Base.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+This documentation is incomplete.
+
+<P>
+There should be some sort of per-(freeside)-user preferences and the
+ability for specific FS::UI:: modules to put their own values there as
+well.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../../FS/UI/Gtk.html">FS::UI::Gtk</A>, <A HREF="../../FS/UI/CGI.html">FS::UI::CGI</A>
+
+
+
+<P>
+<HR>
+<H1><A NAME="HISTORY">HISTORY</A></H1>
+<P>
+$Log: Base.html,v $
+Revision 1.1 1999-08-04 12:13:27 ivan
+new HTML manpages
+ Revision 1.1 1999/08/04 09:03:53 ivan initial checkin of
+module files for proper perl installation
+
+<P>
+Revision 1.1 1999/01/20 09:30:36 ivan skeletal cross-UI UI code.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/UI/CGI.html b/htdocs/docs/man/FS/UI/CGI.html
new file mode 100644
index 000000000..c3efdc746
--- /dev/null
+++ b/htdocs/docs/man/FS/UI/CGI.html
@@ -0,0 +1,115 @@
+<HTML>
+<HEAD>
+<TITLE>FS::UI::CGI - Base class for CGI user-interface objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+ <LI><A HREF="#HISTORY">HISTORY</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::UI::CGI - Base class for CGI user-interface objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::UI::CGI;
+ use FS::UI::some_table;
+</PRE>
+<P>
+<PRE> $interface = new FS::UI::some_table;
+</PRE>
+<P>
+<PRE> $error = $interface-&gt;browse;
+ $error = $interface-&gt;search;
+ $error = $interface-&gt;view;
+ $error = $interface-&gt;edit;
+ $error = $interface-&gt;process;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::UI::CGI object represents a CGI interface object.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new</A></STRONG><DD>
+<DT><STRONG><A NAME="item__header">_header</A></STRONG><DD>
+<DT><STRONG><A NAME="item__footer">_footer</A></STRONG><DD>
+<DT><STRONG><A NAME="item_interface">interface</A></STRONG><DD>
+<P>
+Returns the string `CGI'. Useful for the author of a table-specific UI
+class to conditionally specify certain behaviour.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: CGI.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+This documentation is incomplete.
+
+<P>
+In _Tableborder, headers should be links that sort on their fields.
+
+<P>
+_Link uses a constant <CODE>$BASE_URL</CODE>
+
+<P>
+_Link passes the arguments as a manually-constructed GET string instead of
+POSTing, for compatability while the web interface is upgraded. Once this
+is done it should pass arguements properly (i.e. as a POST, 8-bit clean)
+
+<P>
+Still some small bits of widget code same as FS::UI::Gtk.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../../FS/UI/Base.html">FS::UI::Base</A>
+
+
+
+<P>
+<HR>
+<H1><A NAME="HISTORY">HISTORY</A></H1>
+<P>
+$Log: CGI.html,v $
+Revision 1.1 1999-08-04 12:13:27 ivan
+new HTML manpages
+ Revision 1.1 1999/08/04 09:03:53 ivan initial checkin of
+module files for proper perl installation
+
+<P>
+Revision 1.1 1999/01/20 09:30:36 ivan skeletal cross-UI UI code.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/UI/Gtk.html b/htdocs/docs/man/FS/UI/Gtk.html
new file mode 100644
index 000000000..cb2a864ac
--- /dev/null
+++ b/htdocs/docs/man/FS/UI/Gtk.html
@@ -0,0 +1,112 @@
+<HTML>
+<HEAD>
+<TITLE>FS::UI::Gtk - Base class for Gtk user-interface objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+ <LI><A HREF="#HISTORY">HISTORY</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::UI::Gtk - Base class for Gtk user-interface objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::UI::Gtk;
+ use FS::UI::some_table;
+</PRE>
+<P>
+<PRE> $interface = new FS::UI::some_table;
+</PRE>
+<P>
+<PRE> $error = $interface-&gt;browse;
+ $error = $interface-&gt;search;
+ $error = $interface-&gt;view;
+ $error = $interface-&gt;edit;
+ $error = $interface-&gt;process;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::UI::Gtk object represents a Gtk user interface object.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new</A></STRONG><DD>
+<DT><STRONG><A NAME="item_interface">interface</A></STRONG><DD>
+<P>
+Returns the string `Gtk'. Useful for the author of a table-specific UI
+class to conditionally specify certain behaviour.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: Gtk.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+This documentation is incomplete.
+
+<P>
+_Tableborder is just a _Table now. _Tableborders should scroll (but not the
+headers) and need and need more decoration. (data in white section ala
+gtksql and sliding field widths) headers should be buttons that callback to
+sort on their fields.
+
+<P>
+There should be a persistant, per-(freeside)-user store for window
+positions and sizes and sort fields etc (see <A HREF="../../FS/UI/CGI.html#BUGS">BUGS</A>.
+
+<P>
+Still some small bits of widget code same as FS::UI::CGI.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../../FS/UI/Base.html">FS::UI::Base</A>
+
+
+
+<P>
+<HR>
+<H1><A NAME="HISTORY">HISTORY</A></H1>
+<P>
+$Log: Gtk.html,v $
+Revision 1.1 1999-08-04 12:13:27 ivan
+new HTML manpages
+ Revision 1.1 1999/08/04 09:03:53 ivan initial checkin of
+module files for proper perl installation
+
+<P>
+Revision 1.1 1999/01/20 09:30:36 ivan skeletal cross-UI UI code.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/UI/agent.html b/htdocs/docs/man/FS/UI/agent.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/htdocs/docs/man/FS/UI/agent.html
diff --git a/htdocs/docs/man/FS/UID.html b/htdocs/docs/man/FS/UID.html
new file mode 100644
index 000000000..34444623a
--- /dev/null
+++ b/htdocs/docs/man/FS/UID.html
@@ -0,0 +1,160 @@
+<HTML>
+<HEAD>
+<TITLE>FS::UID - Subroutines for database login and assorted other stuff</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#SUBROUTINES">SUBROUTINES</A>
+ <LI><A HREF="#CALLBACKS">CALLBACKS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::UID - Subroutines for database login and assorted other stuff
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::UID qw(adminsuidsetup cgisuidsetup dbh datasrc getotaker
+ checkeuid checkruid swapuid);
+</PRE>
+<P>
+<PRE> adminsuidsetup $user;
+</PRE>
+<P>
+<PRE> $cgi = new CGI;
+ $dbh = cgisuidsetup($cgi);
+</PRE>
+<P>
+<PRE> $dbh = dbh;
+</PRE>
+<P>
+<PRE> $datasrc = datasrc;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+Provides a hodgepodge of subroutines.
+
+<P>
+<HR>
+<H1><A NAME="SUBROUTINES">SUBROUTINES</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_adminsuidsetup">adminsuidsetup USER</A></STRONG><DD>
+<P>
+Sets the user to USER (see config.html from the base documentation). Cleans
+the environment. Make sure the script is running as freeside, or setuid
+freeside. Opens a connection to the database. Swaps real and effective
+UIDs. Runs any defined callbacks (see below). Returns the DBI database
+handle (usually you don't need this).
+
+<DT><STRONG><A NAME="item_cgisuidsetup">cgisuidsetup CGI_object</A></STRONG><DD>
+<P>
+Stores the CGI (see <A HREF=".././FS/CGI.html#">the CGI manpage</A>) object for later use. (CGI::Base is depriciated) Runs adminsuidsetup.
+
+<DT><STRONG><A NAME="item_cgi">cgi</A></STRONG><DD>
+<P>
+Returns the CGI (see <A HREF=".././FS/CGI.html#">the CGI manpage</A>) object.
+
+<DT><STRONG><A NAME="item_dbh">dbh</A></STRONG><DD>
+<P>
+Returns the DBI database handle.
+
+<DT><STRONG><A NAME="item_datasrc">datasrc</A></STRONG><DD>
+<P>
+Returns the DBI data source.
+
+<DT><STRONG><A NAME="item_getotaker">getotaker</A></STRONG><DD>
+<P>
+Returns the current Freeside user.
+
+<DT><STRONG><A NAME="item_cgisetotaker">cgisetotaker</A></STRONG><DD>
+<P>
+Sets and returns the CGI REMOTE_USER. <A HREF="#item__cgi">$cgi</A> should
+be defined as a CGI.pm object. Support for CGI::Base and derived classes is
+depriciated.
+
+<DT><STRONG><A NAME="item_checkeuid">checkeuid</A></STRONG><DD>
+<P>
+Returns true if effective UID is that of the freeside user.
+
+<DT><STRONG><A NAME="item_checkruid">checkruid</A></STRONG><DD>
+<P>
+Returns true if the real UID is that of the freeside user.
+
+<DT><STRONG><A NAME="item_swapuid">swapuid</A></STRONG><DD>
+<P>
+Swaps real and effective UIDs.
+
+<DT><STRONG><A NAME="item_getsecrets">getsecrets [ USER ]</A></STRONG><DD>
+<P>
+Sets the user to USER, if supplied. Sets and returns the DBI datasource,
+username and password for this user from the
+`/usr/local/etc/freeside/mapsecrets' file.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="CALLBACKS">CALLBACKS</A></H1>
+<P>
+Warning: this interface is likely to change in future releases.
+
+<P>
+A package can install a callback to be run in adminsuidsetup by putting a
+coderef into the hash %FS::UID::callback :
+
+<P>
+<PRE> $coderef = sub { warn &quot;Hi, I'm returning your call!&quot; };
+ $FS::UID::callback{'Package::Name'};
+</PRE>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: UID.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Too many package-global variables.
+
+<P>
+Not OO.
+
+<P>
+No capabilities yet. When mod_perl and Authen::DBI are implemented,
+cgisuidsetup will go away as well.
+
+<P>
+Goes through contortions to support non-OO syntax with multiple datasrc's.
+
+<P>
+Callbacks are inelegant.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF=".././FS/CGI.html#">the CGI manpage</A>, <EM>DBI</EM>, config.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/agent.html b/htdocs/docs/man/FS/agent.html
new file mode 100644
index 000000000..bdbf019c5
--- /dev/null
+++ b/htdocs/docs/man/FS/agent.html
@@ -0,0 +1,130 @@
+<HTML>
+<HEAD>
+<TITLE>FS::agent - Object methods for agent records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::agent - Object methods for agent records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::agent;
+</PRE>
+<P>
+<PRE> $record = new FS::agent \%hash;
+ $record = new FS::agent { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $agent_type = $record-&gt;agent_type;
+</PRE>
+<P>
+<PRE> $hashref = $record-&gt;pkgpart_hashref;
+ #may purchase $pkgpart if $hashref-&gt;{$pkgpart};
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::agent object represents an agent. Every customer has an agent.
+Agents can be used to track things like resellers or salespeople. FS::agent
+inherits from FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_agemtnum">agemtnum - primary key (assigned automatically for new agents)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_agent">agent - Text name of this agent</A></STRONG><DD>
+<DT><STRONG><A NAME="item_typenum">typenum - Agent type. See FS::agent_type</A></STRONG><DD>
+<DT><STRONG><A NAME="item_prog">prog - For future use.</A></STRONG><DD>
+<DT><STRONG><A NAME="item_freq">freq - For future use.</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new agent. To add the agent to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this agent to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this agent from the database. Only agents with no customers can be
+deleted. If there is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid agent. If there is an error,
+returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+<DT><STRONG><A NAME="item_agent_type">agent_type</A></STRONG><DD>
+<P>
+Returns the FS::agent_type object (see <A HREF="../FS/agent_type.html">FS::agent_type</A>) for this agent.
+
+<DT><STRONG><A NAME="item_pkgpart_hashref">pkgpart_hashref</A></STRONG><DD>
+<P>
+Returns a hash reference. The keys of the hash are pkgparts. The value is
+true iff this agent may purchase the specified package definition. See
+<A HREF="../FS/part_pkg.html">FS::part_pkg</A>.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: agent.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/agent_type.html">FS::agent_type</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>, <A HREF="../FS/part_pkg.html">FS::part_pkg</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/agent_type.html b/htdocs/docs/man/FS/agent_type.html
new file mode 100644
index 000000000..25ed652da
--- /dev/null
+++ b/htdocs/docs/man/FS/agent_type.html
@@ -0,0 +1,138 @@
+<HTML>
+<HEAD>
+<TITLE>FS::agent_type - Object methods for agent_type records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::agent_type - Object methods for agent_type records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::agent_type;
+</PRE>
+<P>
+<PRE> $record = new FS::agent_type \%hash;
+ $record = new FS::agent_type { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $hashref = $record-&gt;pkgpart_hashref;
+ #may purchase $pkgpart if $hashref-&gt;{$pkgpart};
+</PRE>
+<P>
+<PRE> @type_pkgs = $record-&gt;type_pkgs;
+</PRE>
+<P>
+<PRE> @pkgparts = $record-&gt;pkgpart;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::agent_type object represents an agent type. Every agent (see
+<A HREF="../FS/agent.html">FS::agent</A>) has an agent type. Agent types define which packages (see
+<A HREF="../FS/part_pkg.html">FS::part_pkg</A>) may be purchased by customers (see <A HREF="../FS/cust_main.html">FS::cust_main</A>), via FS::type_pkgs records (see <A HREF="../FS/type_pkgs.html">FS::type_pkgs</A>). FS::agent_type inherits from FS::Record. The following fields are
+currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_typenum">typenum - primary key (assigned automatically for new agent types)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_atype">atype - Text name of this agent type</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new agent type. To add the agent type to the database, see
+<A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this agent type to the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this agent type from the database. Only agent types with no agents
+can be deleted. If there is an error, returns the error, otherwise returns
+false.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid agent type. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+<DT><STRONG><A NAME="item_pkgpart_hashref">pkgpart_hashref</A></STRONG><DD>
+<P>
+Returns a hash reference. The keys of the hash are pkgparts. The value is
+true iff this agent may purchase the specified package definition. See
+<A HREF="../FS/part_pkg.html">FS::part_pkg</A>.
+
+<DT><STRONG><A NAME="item_type_pkgs">type_pkgs</A></STRONG><DD>
+<P>
+Returns all FS::type_pkgs objects (see <A HREF="../FS/type_pkgs.html">FS::type_pkgs</A>) for this agent type.
+
+<DT><STRONG><A NAME="item_pkgpart">pkgpart</A></STRONG><DD>
+<P>
+Returns the pkgpart of all package definitions (see <A HREF="../FS/part_pkg.html">FS::part_pkg</A>) for this agent type.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: agent_type.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/agent.html">FS::agent</A>, <A HREF="../FS/type_pkgs.html">FS::type_pkgs</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>,
+<A HREF="../FS/part_pkg.html">FS::part_pkg</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_bill.html b/htdocs/docs/man/FS/cust_bill.html
new file mode 100644
index 000000000..c28aa85a1
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_bill.html
@@ -0,0 +1,184 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_bill - Object methods for cust_bill records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_bill - Object methods for cust_bill records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_bill;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_bill \%hash;
+ $record = new FS::cust_bill { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> ( $total_previous_balance, @previous_cust_bill ) = $record-&gt;previous;
+</PRE>
+<P>
+<PRE> @cust_bill_pkg_objects = $cust_bill-&gt;cust_bill_pkg;
+</PRE>
+<P>
+<PRE> ( $total_previous_credits, @previous_cust_credit ) = $record-&gt;cust_credit;
+</PRE>
+<P>
+<PRE> @cust_pay_objects = $cust_bill-&gt;cust_pay;
+</PRE>
+<P>
+<PRE> @lines = $cust_bill-&gt;print_text;
+ @lines = $cust_bill-&gt;print_text $time;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_bill object represents an invoice. FS::cust_bill inherits from
+FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_invnum">invnum - primary key (assigned automatically for new invoices)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_custnum">custnum - customer (see FS::cust_main)</A></STRONG><DD>
+<DT><STRONG><A NAME="item__date">_date - specified as a UNIX timestamp; see perlfunc/&quot;time&quot;. Also see
+Time::Local and Date::Parse for conversion functions.</A></STRONG><DD>
+<DT><STRONG><A NAME="item_charged">charged - amount of this invoice</A></STRONG><DD>
+<DT><STRONG><A NAME="item_owed">owed - amount still outstanding on this invoice, which is charged minus
+all payments (see FS::cust_pay).</A></STRONG><DD>
+<DT><STRONG><A NAME="item_printed">printed - how many times this invoice has been printed automatically
+(see FS::cust_main/&quot;collect&quot;).</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new invoice. To add the invoice to the database, see <A HREF="#insert">insert</A>. Invoices are normally created by calling the bill method of a customer
+object (see <A HREF="../FS/cust_main.html">FS::cust_main</A>).
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this invoice to the database (``Posts'' the invoice). If there is an
+error, returns the error, otherwise returns false.
+
+<P>
+When adding new invoices, owed must be charged (or null, in which case it
+is automatically set to charged).
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented. I don't remove invoices because there would then
+be no record you ever posted this invoice (which is bad, no?)
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces the OLD_RECORD with this one in the database. If there is an
+error, returns the error, otherwise returns false.
+
+<P>
+Only owed and printed may be changed. Owed is normally updated by creating
+and inserting a payment (see <A HREF="../FS/cust_pay.html">FS::cust_pay</A>). Printed is normally updated by calling the collect method of a customer
+object (see <A HREF="../FS/cust_main.html">FS::cust_main</A>).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid invoice. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+<DT><STRONG><A NAME="item_previous">previous</A></STRONG><DD>
+<P>
+Returns a list consisting of the total previous balance for this customer,
+followed by the previous outstanding invoices (as FS::cust_bill objects
+also).
+
+<DT><STRONG><A NAME="item_cust_bill_pkg">cust_bill_pkg</A></STRONG><DD>
+<P>
+Returns the line items (see <A HREF="../FS/cust_bill_pkg.html">FS::cust_bill_pkg</A>) for this invoice.
+
+<DT><STRONG><A NAME="item_cust_credit">cust_credit</A></STRONG><DD>
+<P>
+Returns a list consisting of the total previous credited (see
+<A HREF="../FS/cust_credit.html">FS::cust_credit</A>) for this customer, followed by the previous outstanding credits
+(FS::cust_credit objects).
+
+<DT><STRONG><A NAME="item_cust_pay">cust_pay</A></STRONG><DD>
+<P>
+Returns all payments (see <A HREF="../FS/cust_pay.html">FS::cust_pay</A>) for this invoice.
+
+<DT><STRONG><A NAME="item_print_text">print_text [TIME];</A></STRONG><DD>
+<P>
+Returns an ASCII invoice, as a list of lines.
+
+<P>
+TIME an optional value used to control the printing of overdue messages.
+The default is now. It isn't the date of the invoice; that's the `_date'
+field. It is specified as a UNIX timestamp; see <EM>perlfunc</EM>. Also see
+<A HREF="../Time/Local.html">Time::Local</A> and <A HREF="../Date/Parse.html">Date::Parse</A> for conversion functions.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_bill.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The delete method.
+
+<P>
+print_text formatting (and some logic :/) is in source, but needs to be
+slurped in from a file. Also number of lines ($=).
+
+<P>
+missing print_ps for a nice postscript copy (maybe HylaFAX-cover-page-style
+or something similar so the look can be completely customized?)
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>, <A HREF="../FS/cust_pay.html">FS::cust_pay</A>, <A HREF="../FS/cust_bill_pkg.html">FS::cust_bill_pkg</A>,
+<A HREF="../FS/cust_credit.html">FS::cust_credit</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_bill_pkg.html b/htdocs/docs/man/FS/cust_bill_pkg.html
new file mode 100644
index 000000000..229e88b5f
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_bill_pkg.html
@@ -0,0 +1,119 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_bill_pkg - Object methods for cust_bill_pkg records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_bill_pkg - Object methods for cust_bill_pkg records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_bill_pkg;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_bill_pkg \%hash;
+ $record = new FS::cust_bill_pkg { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_bill_pkg object represents an invoice line item.
+FS::cust_bill_pkg inherits from FS::Record. The following fields are
+currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_invnum">invnum - invoice (see FS::cust_bill)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_pkgnum">pkgnum - package (see FS::cust_pkg)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_setup">setup - setup fee</A></STRONG><DD>
+<DT><STRONG><A NAME="item_recur">recur - recurring fee</A></STRONG><DD>
+<DT><STRONG><A NAME="item_sdate">sdate - starting date of recurring fee</A></STRONG><DD>
+<DT><STRONG><A NAME="item_edate">edate - ending date of recurring fee</A></STRONG><DD>
+</DL>
+<P>
+sdate and edate are specified as UNIX timestamps; see <EM>perlfunc</EM>. Also see <A HREF="../Time/Local.html">Time::Local</A> and <A HREF="../Date/Parse.html">Date::Parse</A> for conversion functions.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new line item. To add the line item to the database, see
+<A HREF="#insert">insert</A>. Line items are normally created by calling the bill method of a customer
+object (see <A HREF="../FS/cust_main.html">FS::cust_main</A>).
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this line item to the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented. I don't remove line items because there would then
+be no record the items ever existed (which is bad, no?)
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Currently unimplemented. This would be even more of an accounting nightmare
+than deleteing the items. Just don't do it.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid line item. If there is an
+error, returns the error, otherwise returns false. Called by the insert
+method.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_bill_pkg.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_bill.html">FS::cust_bill</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_credit.html b/htdocs/docs/man/FS/cust_credit.html
new file mode 100644
index 000000000..5683fcd0d
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_credit.html
@@ -0,0 +1,126 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_credit - Object methods for cust_credit records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_credit - Object methods for cust_credit records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_credit;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_credit \%hash;
+ $record = new FS::cust_credit { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_credit object represents a credit. FS::cust_credit inherits
+from FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_crednum">crednum - primary key (assigned automatically for new credits)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_custnum">custnum - customer (see FS::cust_main)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_amount">amount - amount of the credit</A></STRONG><DD>
+<DT><STRONG><A NAME="item_credited">credited - how much of this credit that is still outstanding, which is
+amount minus all refunds (see FS::cust_refund).</A></STRONG><DD>
+<DT><STRONG><A NAME="item__date">_date - specified as a UNIX timestamp; see perlfunc/&quot;time&quot;. Also see
+Time::Local and Date::Parse for conversion functions.</A></STRONG><DD>
+<DT><STRONG><A NAME="item_otaker">otaker - order taker (assigned automatically, see FS::UID)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_reason">reason - text</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new credit. To add the credit to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this credit to the database (``Posts'' the credit). If there is an
+error, returns the error, otherwise returns false.
+
+<P>
+When adding new invoices, credited must be amount (or null, in which case
+it is automatically set to amount).
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces the OLD_RECORD with this one in the database. If there is an
+error, returns the error, otherwise returns false.
+
+<P>
+Only credited may be changed. Credited is normally updated by creating and
+inserting a refund (see <A HREF="../FS/cust_refund.html">FS::cust_refund</A>).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid credit. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_credit.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The delete method.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_refund.html">FS::cust_refund</A>, <A HREF="../FS/cust_bill.html">FS::cust_bill</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_main.html b/htdocs/docs/man/FS/cust_main.html
new file mode 100644
index 000000000..5e0b8eef7
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_main.html
@@ -0,0 +1,277 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_main - Object methods for cust_main records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_main - Object methods for cust_main records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_main;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_main \%hash;
+ $record = new FS::cust_main { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> @cust_pkg = $record-&gt;all_pkgs;
+</PRE>
+<P>
+<PRE> @cust_pkg = $record-&gt;ncancelled_pkgs;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;bill;
+ $error = $record-&gt;bill %options;
+ $error = $record-&gt;bill 'time' =&gt; $time;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;collect;
+ $error = $record-&gt;collect %options;
+ $error = $record-&gt;collect 'invoice_time' =&gt; $time,
+ 'batch_card' =&gt; 'yes',
+ 'report_badcard' =&gt; 'yes',
+ ;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_main object represents a customer. FS::cust_main inherits from
+FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_custnum">custnum - primary key (assigned automatically for new customers)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_agentnum">agentnum - agent (see FS::agent)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_refnum">refnum - referral (see FS::part_referral)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_first">first - name</A></STRONG><DD>
+<DT><STRONG><A NAME="item_last">last - name</A></STRONG><DD>
+<DT><STRONG><A NAME="item_ss">ss - social security number (optional)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_company">company - (optional)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_address1">address1</A></STRONG><DD>
+<DT><STRONG><A NAME="item_address2">address2 - (optional)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_city">city</A></STRONG><DD>
+<DT><STRONG><A NAME="item_county">county - (optional, see FS::cust_main_county)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_state">state - (see FS::cust_main_county)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_zip">zip</A></STRONG><DD>
+<DT><STRONG><A NAME="item_country">country - (see FS::cust_main_county)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_daytime">daytime - phone (optional)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_night">night - phone (optional)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_fax">fax - phone (optional)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payby">payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payinfo">payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_paydate">paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payname">payname - name on card or billing name</A></STRONG><DD>
+<DT><STRONG><A NAME="item_tax">tax - tax exempt, empty or `Y'</A></STRONG><DD>
+<DT><STRONG><A NAME="item_otaker">otaker - order taker (assigned automatically, see FS::UID)</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new customer. To add the customer to the database, see <A HREF="#insert">insert</A>.
+
+<P>
+Note that this stores the hash reference, not a distinct copy of the hash
+it points to. You can ask the object for a copy with the <EM>hash</EM> method.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this customer to the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete NEW_CUSTNUM</A></STRONG><DD>
+<P>
+This deletes the customer. If there is an error, returns the error,
+otherwise returns false.
+
+<P>
+This will completely remove all traces of the customer record. This is not
+what you want when a customer cancels service; for that, cancel all of the
+customer's packages (see <A HREF="../FS/cust_pkg.html#cancel">cancel</A>).
+
+<P>
+If the customer has any packages, you need to pass a new (valid) customer
+number for those packages to be transferred to.
+
+<P>
+You can't delete a customer with invoices (see <A HREF="../FS/cust_bill.html">FS::cust_bill</A>), or credits (see <A HREF="../FS/cust_credit.html">FS::cust_credit</A>).
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces the OLD_RECORD with this one in the database. If there is an
+error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid customer record. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and repalce methods.
+
+<DT><STRONG><A NAME="item_all_pkgs">all_pkgs</A></STRONG><DD>
+<P>
+Returns all packages (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>) for this customer.
+
+<DT><STRONG><A NAME="item_ncancelled_pkgs">ncancelled_pkgs</A></STRONG><DD>
+<P>
+Returns all non-cancelled packages (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>) for this customer.
+
+<DT><STRONG><A NAME="item_bill">bill OPTIONS</A></STRONG><DD>
+<P>
+Generates invoices (see <A HREF="../FS/cust_bill.html">FS::cust_bill</A>) for this customer. Usually used in conjunction with the collect method.
+
+<P>
+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
+<EM>perlfunc</EM>). Also see <A HREF="../Time/Local.html">Time::Local</A> and <A HREF="../Date/Parse.html">Date::Parse</A> for conversion functions.
+
+<P>
+If there is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_collect">collect OPTIONS</A></STRONG><DD>
+<P>
+(Attempt to) collect money for this customer's outstanding invoices (see
+<A HREF="../FS/cust_bill.html">FS::cust_bill</A>). Usually used after the bill method.
+
+<P>
+Depending on the value of `payby', this may print an invoice (`BILL'),
+charge a credit card (`CARD'), or just add any necessary (pseudo-)payment
+(`COMP').
+
+<P>
+If there is an error, returns the error, otherwise returns false.
+
+<P>
+Currently available options are:
+
+<P>
+invoice_time - Use this time when deciding when to print invoices and late
+notices on those invoices. The default is now. It is specified as a UNIX
+timestamp; see <EM>perlfunc</EM>). Also see <A HREF="../Time/Local.html">Time::Local</A> and <A HREF="../Date/Parse.html">Date::Parse</A>
+for conversion functions.
+
+<P>
+batch_card - Set this true to batch cards (see <A HREF=".././FS/cust_pay_batch.html#">the cust_pay_batch manpage</A>). By default, cards are processed immediately, which will generate an
+error if CyberCash is not installed.
+
+<P>
+report_badcard - Set this true if you want bad card transactions to return
+an error. By default, they don't.
+
+<DT><STRONG><A NAME="item_total_owed">total_owed</A></STRONG><DD>
+<P>
+Returns the total owed for this customer on all invoices (see <A HREF="../FS/cust_bill.html">FS::cust_bill</A>).
+
+<DT><STRONG><A NAME="item_total_credited">total_credited</A></STRONG><DD>
+<P>
+Returns the total credits (see <A HREF="../FS/cust_credit.html">FS::cust_credit</A>) for this customer.
+
+<DT><STRONG><A NAME="item_balance">balance</A></STRONG><DD>
+<P>
+Returns the balance for this customer (total owed minus total credited).
+
+<DT><STRONG><A NAME="item_invoicing_list">invoicing_list [ ARRAYREF ]</A></STRONG><DD>
+<P>
+If an arguement is given, sets these email addresses as invoice recipients
+(see <A HREF="../FS/cust_main_invoice.html">FS::cust_main_invoice</A>). Errors are not fatal and are not reported (except as warnings), so use
+check_invoicing_list first.
+
+<P>
+Returns a list of email addresses (with svcnum entries expanded).
+
+<P>
+Note: You can clear the invoicing list by passing an empty ARRAYREF. You
+can check it without disturbing anything by passing nothing.
+
+<P>
+This interface may change in the future.
+
+<DT><STRONG><A NAME="item_check_invoicing_list">check_invoicing_list ARRAYREF</A></STRONG><DD>
+<P>
+Checks these arguements as valid input for the invoicing_list method. If
+there is an error, returns the error, otherwise returns false.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_main.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The delete method.
+
+<P>
+The delete method should possibly take an FS::cust_main object reference
+instead of a scalar customer number.
+
+<P>
+Bill and collect options should probably be passed as references instead of
+a list.
+
+<P>
+CyberCash v2 forces us to define some variables in package main.
+
+<P>
+There should probably be a configuration file with a list of allowed credit
+card types.
+
+<P>
+CyberCash is the only processor.
+
+<P>
+No multiple currency support (probably a larger project than just this
+module).
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>, <A HREF="../FS/cust_bill.html">FS::cust_bill</A>, <A HREF="../FS/cust_credit.html">FS::cust_credit</A>
+
+<A HREF="../FS/cust_pay_batch.html">FS::cust_pay_batch</A>, <A HREF="../FS/agent.html">FS::agent</A>, <A HREF="../FS/part_referral.html">FS::part_referral</A>,
+<A HREF="../FS/cust_main_county.html">FS::cust_main_county</A>, <A HREF="../FS/cust_main_invoice.html">FS::cust_main_invoice</A>,
+<A HREF="../FS/UID.html">FS::UID</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_main_county.html b/htdocs/docs/man/FS/cust_main_county.html
new file mode 100644
index 000000000..a3c1f400c
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_main_county.html
@@ -0,0 +1,113 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_main_county - Object methods for cust_main_county objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_main_county - Object methods for cust_main_county objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_main_county;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_main_county \%hash;
+ $record = new FS::cust_main_county { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_main_county object represents a tax rate, defined by locale.
+FS::cust_main_county inherits from FS::Record. The following fields are
+currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_taxnum">taxnum - primary key (assigned automatically for new tax rates)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_state">state</A></STRONG><DD>
+<DT><STRONG><A NAME="item_county">county</A></STRONG><DD>
+<DT><STRONG><A NAME="item_country">country</A></STRONG><DD>
+<DT><STRONG><A NAME="item_tax">tax - percentage</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new tax rate. To add the tax rate to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this tax rate to the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this tax rate from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces the OLD_RECORD with this one in the database. If there is an
+error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid tax rate. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_main_county.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>, <A HREF="../FS/cust_bill.html">FS::cust_bill</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_main_invoice.html b/htdocs/docs/man/FS/cust_main_invoice.html
new file mode 100644
index 000000000..2fc22b306
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_main_invoice.html
@@ -0,0 +1,128 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_main_invoice - Object methods for cust_main_invoice records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_main_invoice - Object methods for cust_main_invoice records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_main_invoice;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_main_invoice \%hash;
+ $record = new FS::cust_main_invoice { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $email_address = $record-&gt;address;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_main_invoice object represents an invoice destination.
+FS::cust_main_invoice inherits from FS::Record. The following fields are
+currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_destnum">destnum - primary key</A></STRONG><DD>
+<DT><STRONG><A NAME="item_custnum">custnum - customer (see FS::cust_main)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_dest">dest - Invoice destination: If numeric, a &lt;a href=&quot;#svc_acct&quot;&gt;svcnum&lt;/a&gt;, if string, a literal email address, or `POST' to enable mailing (the default if no cust_main_invoice records exist)</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new invoice destination. To add the invoice destination to the
+database, see <A HREF="#insert">insert</A>.
+
+<P>
+Note that this stores the hash reference, not a distinct copy of the hash
+it points to. You can ask the object for a copy with the <EM>hash</EM> method.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Delete this record from the database.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces the OLD_RECORD with this one in the database. If there is an
+error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid invoice destination. If
+there is an error, returns the error, otherwise returns false. Called by
+the insert and repalce methods.
+
+<DT><STRONG><A NAME="item_checkdest">checkdest</A></STRONG><DD>
+<P>
+Checks the dest field only.
+
+<DT><STRONG><A NAME="item_address">address</A></STRONG><DD>
+<P>
+Returns the literal email address for this record (or `POST').
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_main_invoice.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>
+
+
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_pay.html b/htdocs/docs/man/FS/cust_pay.html
new file mode 100644
index 000000000..026745e73
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_pay.html
@@ -0,0 +1,116 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_pay - Object methods for cust_pay objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_pay - Object methods for cust_pay objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_pay;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_pay \%hash;
+ $record = new FS::cust_pay { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_pay object represents a payment. FS::cust_pay inherits from
+FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_paynum">paynum - primary key (assigned automatically for new payments)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_invnum">invnum - Invoice (see FS::cust_bill)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_paid">paid - Amount of this payment</A></STRONG><DD>
+<DT><STRONG><A NAME="item__date">_date - specified as a UNIX timestamp; see perlfunc/&quot;time&quot;. Also see
+Time::Local and Date::Parse for conversion functions.</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payby">payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payinfo">payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_paybatch">paybatch - text field for tracking card processing</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new payment. To add the payment to the databse, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this payment to the databse, and updates the invoice (see
+<A HREF="../FS/cust_bill.html">FS::cust_bill</A>).
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented (accounting reasons).
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Currently unimplemented (accounting reasons).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid payment. If there is an
+error, returns the error, otherwise returns false. Called by the insert
+method.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_pay.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Delete and replace methods.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_bill.html">FS::cust_bill</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_pay_batch.html b/htdocs/docs/man/FS/cust_pay_batch.html
new file mode 100644
index 000000000..1a5189e6b
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_pay_batch.html
@@ -0,0 +1,134 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_pay_batch - Object methods for batch cards</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_pay_batch - Object methods for batch cards
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_pay_batch;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_pay_batch \%hash;
+ $record = new FS::cust_pay_batch { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_pay_batch object represents a credit card transaction ready to
+be batched (sent to a processor). FS::cust_pay_batch inherits from
+FS::Record. Typically called by the collect method of an FS::cust_main
+object. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_trancode">trancode - 77 for charges</A></STRONG><DD>
+<DT><STRONG><A NAME="item_cardnum">cardnum</A></STRONG><DD>
+<DT><STRONG><A NAME="item_exp">exp - card expiration</A></STRONG><DD>
+<DT><STRONG><A NAME="item_amount">amount</A></STRONG><DD>
+<DT><STRONG><A NAME="item_invnum">invnum - invoice</A></STRONG><DD>
+<DT><STRONG><A NAME="item_custnum">custnum - customer</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payname">payname - name on card</A></STRONG><DD>
+<DT><STRONG><A NAME="item_first">first - name</A></STRONG><DD>
+<DT><STRONG><A NAME="item_last">last - name</A></STRONG><DD>
+<DT><STRONG><A NAME="item_address1">address1</A></STRONG><DD>
+<DT><STRONG><A NAME="item_address2">address2</A></STRONG><DD>
+<DT><STRONG><A NAME="item_city">city</A></STRONG><DD>
+<DT><STRONG><A NAME="item_state">state</A></STRONG><DD>
+<DT><STRONG><A NAME="item_zip">zip</A></STRONG><DD>
+<DT><STRONG><A NAME="item_country">country</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new record. To add the record to the database, see <A HREF="#insert">insert</A>.
+
+<P>
+Note that this stores the hash reference, not a distinct copy of the hash
+it points to. You can ask the object for a copy with the <EM>hash</EM> method.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Delete this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+#inactive # #Replaces the OLD_RECORD with this one in the database. If
+there is an error, #returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid transaction. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+repalce methods.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_pay_batch.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+There should probably be a configuration file with a list of allowed credit
+card types.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/cust_main.html">FS::cust_main</A>, <A HREF="../FS/Record.html">FS::Record</A>
+
+
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_pkg.html b/htdocs/docs/man/FS/cust_pkg.html
new file mode 100644
index 000000000..e105a30df
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_pkg.html
@@ -0,0 +1,254 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_pkg - Object methods for cust_pkg objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#SUBROUTINES">SUBROUTINES</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_pkg - Object methods for cust_pkg objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_pkg;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_pkg \%hash;
+ $record = new FS::cust_pkg { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;cancel;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;suspend;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;unsuspend;
+</PRE>
+<P>
+<PRE> $part_pkg = $record-&gt;part_pkg;
+</PRE>
+<P>
+<PRE> @labels = $record-&gt;labels;
+</PRE>
+<P>
+<PRE> $error = FS::cust_pkg::order( $custnum, \@pkgparts );
+ $error = FS::cust_pkg::order( $custnum, \@pkgparts, \@remove_pkgnums ] );
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_pkg object represents a customer billing item. FS::cust_pkg
+inherits from FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_pkgnum">pkgnum - primary key (assigned automatically for new billing items)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_custnum">custnum - Customer (see FS::cust_main)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_pkgpart">pkgpart - Billing item definition (see FS::part_pkg)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_setup">setup - date</A></STRONG><DD>
+<DT><STRONG><A NAME="item_bill">bill - date</A></STRONG><DD>
+<DT><STRONG><A NAME="item_susp">susp - date</A></STRONG><DD>
+<DT><STRONG><A NAME="item_expire">expire - date</A></STRONG><DD>
+<DT><STRONG><A NAME="item_cancel">cancel - date</A></STRONG><DD>
+<DT><STRONG><A NAME="item_otaker">otaker - order taker (assigned automatically if null, see FS::UID)</A></STRONG><DD>
+</DL>
+<P>
+Note: setup, bill, susp, expire and cancel are specified as UNIX
+timestamps; see <EM>perlfunc</EM>. Also see <A HREF="../Time/Local.html">Time::Local</A> and <A HREF="../Date/Parse.html">Date::Parse</A> for conversion functions.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Create a new billing item. To add the item to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this billing item to the database (``Orders'' the item). If there is
+an error, returns the error, otherwise returns false.
+
+<P>
+sub insert { my <CODE>$self</CODE> = shift;
+
+<P>
+<PRE> # custnum might not have have been defined in sub check (for one-shot new
+ # customers), so check it here instead
+</PRE>
+<P>
+<PRE> my $error = $self-&gt;ut_number('custnum');
+ return $error if $error
+</PRE>
+<P>
+<PRE> return &quot;Unknown customer&quot;
+ unless qsearchs( 'cust_main', { 'custnum' =&gt; $self-&gt;custnum } );
+</PRE>
+<P>
+<PRE> $self-&gt;SUPER::insert;
+</PRE>
+<P>
+}
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented. You don't want to delete billing items, because
+there would then be no record the customer ever purchased the item.
+Instead, see the cancel method.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces the OLD_RECORD with this one in the database. If there is an
+error, returns the error, otherwise returns false.
+
+<P>
+Currently, custnum, setup, bill, susp, expire, and cancel may be changed.
+
+<P>
+Changing pkgpart may have disasterous effects. See the order subroutine.
+
+<P>
+setup and bill are normally updated by calling the bill method of a
+customer object (see <A HREF="../FS/cust_main.html">FS::cust_main</A>).
+
+<P>
+suspend is normally updated by the suspend and unsuspend methods.
+
+<P>
+cancel is normally updated by the cancel method (and also the order
+subroutine in some cases).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid billing item. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+<DT><STRONG>cancel</STRONG><DD>
+<P>
+Cancels and removes all services (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A> and <A HREF="../FS/part_svc.html">FS::part_svc</A>) in this package, then cancels the package itself (sets the cancel field
+to now).
+
+<P>
+If there is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_suspend">suspend</A></STRONG><DD>
+<P>
+Suspends all services (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A> and <A HREF="../FS/part_svc.html">FS::part_svc</A>) in this package, then suspends the package itself (sets the susp field to
+now).
+
+<P>
+If there is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_unsuspend">unsuspend</A></STRONG><DD>
+<P>
+Unsuspends all services (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A> and <A HREF="../FS/part_svc.html">FS::part_svc</A>) in this package, then unsuspends the package itself (clears the susp
+field).
+
+<P>
+If there is an error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_part_pkg">part_pkg</A></STRONG><DD>
+<P>
+Returns the definition for this billing item, as an FS::part_pkg object
+(see
+<A HREF="../FS/part_pkg.html">FS::part_pkg</A>).
+
+<DT><STRONG><A NAME="item_labels">labels</A></STRONG><DD>
+<P>
+Returns a list of lists, calling the label method for all services (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A>) of this billing item.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="SUBROUTINES">SUBROUTINES</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_order">order CUSTNUM, PKGPARTS_ARYREF, [ REMOVE_PKGNUMS_ARYREF ]</A></STRONG><DD>
+<P>
+CUSTNUM is a customer (see <A HREF="../FS/cust_main.html">FS::cust_main</A>)
+
+<P>
+PKGPARTS is a list of pkgparts specifying the the billing item definitions
+(see
+<A HREF="../FS/part_pkg.html">FS::part_pkg</A>) to order for this customer. Duplicates are of course permitted.
+
+<P>
+REMOVE_PKGNUMS is an optional list of pkgnums specifying the billing items
+to remove for this customer. The services (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A>) are moved to the new billing items. An error is returned if this is not
+possible (see
+<A HREF="../FS/pkg_svc.html">FS::pkg_svc</A>).
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_pkg.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+sub order is not OO. Perhaps it should be moved to FS::cust_main and made
+so?
+
+<P>
+In sub order, the <CODE>@pkgparts</CODE> array (passed by reference) is
+clobbered.
+
+<P>
+Also in sub order, no money is adjusted. Once FS::part_pkg defines a
+standard method to pass dates to the recur_prog expression, it should do
+so.
+
+<P>
+FS::svc_acct, FS::svc_acct_sm, and FS::svc_domain are loaded via 'use' at
+compile time, rather than via 'require' in sub { setup, suspend, unsuspend,
+cancel } because they use %FS::UID::callback to load configuration values.
+Probably need a subroutine which decides what to do based on whether or not
+we've fetched the user yet, rather than a hash. See FS::UID and the TODO.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>, <A HREF="../FS/part_pkg.html">FS::part_pkg</A>, <A HREF="../FS/cust_svc.html">FS::cust_svc</A>
+, <A HREF="../FS/pkg_svc.html">FS::pkg_svc</A>, schema.html from the base documentation
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_refund.html b/htdocs/docs/man/FS/cust_refund.html
new file mode 100644
index 000000000..f1d106c2f
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_refund.html
@@ -0,0 +1,116 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_refund - Object method for cust_refund objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_refund - Object method for cust_refund objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_refund;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_refund \%hash;
+ $record = new FS::cust_refund { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_refund represents a refund. FS::cust_refund inherits from
+FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_refundnum">refundnum - primary key (assigned automatically for new refunds)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_crednum">crednum - Credit (see FS::cust_credit)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_refund">refund - Amount of the refund</A></STRONG><DD>
+<DT><STRONG><A NAME="item__date">_date - specified as a UNIX timestamp; see perlfunc/&quot;time&quot;. Also see
+Time::Local and Date::Parse for conversion functions.</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payby">payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_payinfo">payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_otaker">otaker - order taker (assigned automatically, see FS::UID)</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new refund. To add the refund to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this refund to the database, and updates the credit (see
+<A HREF="../FS/cust_credit.html">FS::cust_credit</A>).
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented (accounting reasons).
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Currently unimplemented (accounting reasons).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid refund. If there is an
+error, returns the error, otherwise returns false. Called by the insert
+method.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_refund.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Delete and replace methods.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_credit.html">FS::cust_credit</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/cust_svc.html b/htdocs/docs/man/FS/cust_svc.html
new file mode 100644
index 000000000..060fb7fa6
--- /dev/null
+++ b/htdocs/docs/man/FS/cust_svc.html
@@ -0,0 +1,134 @@
+<HTML>
+<HEAD>
+<TITLE>FS::cust_svc - Object method for cust_svc objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::cust_svc - Object method for cust_svc objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::cust_svc;
+</PRE>
+<P>
+<PRE> $record = new FS::cust_svc \%hash
+ $record = new FS::cust_svc { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> ($label, $value) = $record-&gt;label;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::cust_svc represents a service. FS::cust_svc inherits from
+FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_svcnum">svcnum - primary key (assigned automatically for new services)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_pkgnum">pkgnum - Package (see FS::cust_pkg)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_svcpart">svcpart - Service definition (see FS::part_svc)</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new service. To add the refund to the database, see <A HREF="#insert">insert</A>. Services are normally created by creating FS::svc_ objects (see
+<A HREF="../FS/svc_acct.html">FS::svc_acct</A>, <A HREF="../FS/svc_domain.html">FS::svc_domain</A>, and <A HREF="../FS/svc_acct_sm.html">FS::svc_acct_sm</A>, among others).
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this service to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this service from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<P>
+Called by the cancel method of the package (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces the OLD_RECORD with this one in the database. If there is an
+error, returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid service. If there is an
+error, returns the error, otehrwise returns false. Called by the insert and
+replace methods.
+
+<DT><STRONG><A NAME="item_label">label</A></STRONG><DD>
+<P>
+Returns a list consisting of: - The name of this service (from part_svc) -
+A meaningful identifier (username, domain, or mail alias) - The table name
+(i.e. svc_domain) for this service
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: cust_svc.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Behaviour of changing the svcpart of cust_svc records is undefined and
+should possibly be prohibited, and pkg_svc records are not checked.
+
+<P>
+pkg_svc records are not checked in general (here).
+
+<P>
+Deleting this record doesn't check or delete the svc_* record associated
+with this record.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>, <A HREF="../FS/part_svc.html">FS::part_svc</A>, <A HREF="../FS/pkg_svc.html">FS::pkg_svc</A>, schema.html from the base documentation
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/dbdef.html b/htdocs/docs/man/FS/dbdef.html
new file mode 100644
index 000000000..9b8274b29
--- /dev/null
+++ b/htdocs/docs/man/FS/dbdef.html
@@ -0,0 +1,97 @@
+<HTML>
+<HEAD>
+<TITLE>FS::dbdef - Database objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::dbdef - Database objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::dbdef;
+</PRE>
+<P>
+<PRE> $dbdef = new FS::dbdef (@dbdef_table_objects);
+ $dbdef = load FS::dbdef &quot;filename&quot;;
+</PRE>
+<P>
+<PRE> $dbdef-&gt;save(&quot;filename&quot;);
+</PRE>
+<P>
+<PRE> $dbdef-&gt;addtable($dbdef_table_object);
+</PRE>
+<P>
+<PRE> @table_names = $dbdef-&gt;tables;
+</PRE>
+<P>
+<PRE> $FS_dbdef_table_object = $dbdef-&gt;table;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+FS::dbdef objects are collections of FS::dbdef_table objects and represnt a
+database (a collection of tables).
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new TABLE, TABLE, ...</A></STRONG><DD>
+<P>
+Creates a new FS::dbdef object
+
+<DT><STRONG><A NAME="item_load">load FILENAME</A></STRONG><DD>
+<P>
+Loads an FS::dbdef object from a file.
+
+<DT><STRONG><A NAME="item_save">save FILENAME</A></STRONG><DD>
+<P>
+Saves an FS::dbdef object to a file.
+
+<DT><STRONG><A NAME="item_addtable">addtable TABLE</A></STRONG><DD>
+<P>
+Adds this FS::dbdef_table object.
+
+<DT><STRONG><A NAME="item_tables">tables</A></STRONG><DD>
+<P>
+Returns the names of all tables.
+
+<DT><STRONG><A NAME="item_table">table TABLENAME</A></STRONG><DD>
+<P>
+Returns the named FS::dbdef_table object.
+
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Each FS::dbdef object should have a name which corresponds to its name
+within the SQL database engine.
+
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>, <A HREF="../FS/Record.html">FS::Record</A>,
+
+</DL>
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/dbdef_colgroup.html b/htdocs/docs/man/FS/dbdef_colgroup.html
new file mode 100644
index 000000000..9c4f7f43d
--- /dev/null
+++ b/htdocs/docs/man/FS/dbdef_colgroup.html
@@ -0,0 +1,86 @@
+<HTML>
+<HEAD>
+<TITLE>FS::dbdef_colgroup - Column group objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::dbdef_colgroup - Column group objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::dbdef_colgroup;
+</PRE>
+<P>
+<PRE> $colgroup = new FS::dbdef_colgroup ( $lol );
+ $colgroup = new FS::dbdef_colgroup (
+ [
+ [ 'single_column' ],
+ [ 'multiple_columns', 'another_column', ],
+ ]
+ );
+</PRE>
+<P>
+<PRE> @sql_lists = $colgroup-&gt;sql_list;
+</PRE>
+<P>
+<PRE> @singles = $colgroup-&gt;singles;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+FS::dbdef_colgroup objects represent sets of sets of columns.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new</A></STRONG><DD>
+<P>
+Creates a new FS::dbdef_colgroup object.
+
+<DT><STRONG><A NAME="item_sql_list">sql_list</A></STRONG><DD>
+<P>
+Returns a flat list of comma-separated values, for SQL statements.
+
+<DT><STRONG><A NAME="item_singles">singles</A></STRONG><DD>
+<P>
+Returns a flat list of all single item lists.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>, <A HREF="../FS/dbdef_unique.html">FS::dbdef_unique</A>, <A HREF="../FS/dbdef_index.html">FS::dbdef_index</A>,
+<A HREF="../FS/dbdef_column.html">FS::dbdef_column</A>, <A HREF="../FS/dbdef.html">FS::dbdef</A>, <EM>perldsc</EM>
+
+
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/dbdef_column.html b/htdocs/docs/man/FS/dbdef_column.html
new file mode 100644
index 000000000..c753b52f7
--- /dev/null
+++ b/htdocs/docs/man/FS/dbdef_column.html
@@ -0,0 +1,118 @@
+<HTML>
+<HEAD>
+<TITLE>FS::dbdef_column - Column object</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::dbdef_column - Column object
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::dbdef_column;
+</PRE>
+<P>
+<PRE> $column_object = new FS::dbdef_column ( $name, $sql_type, '' );
+ $column_object = new FS::dbdef_column ( $name, $sql_type, 'NULL' );
+ $column_object = new FS::dbdef_column ( $name, $sql_type, '', $length );
+ $column_object = new FS::dbdef_column ( $name, $sql_type, 'NULL', $length );
+</PRE>
+<P>
+<PRE> $name = $column_object-&gt;name;
+ $column_object-&gt;name ( 'name' );
+</PRE>
+<P>
+<PRE> $name = $column_object-&gt;type;
+ $column_object-&gt;name ( 'sql_type' );
+</PRE>
+<P>
+<PRE> $name = $column_object-&gt;null;
+ $column_object-&gt;name ( 'NOT NULL' );
+</PRE>
+<P>
+<PRE> $name = $column_object-&gt;length;
+ $column_object-&gt;name ( $length );
+</PRE>
+<P>
+<PRE> $sql_line = $column-&gt;line;
+ $sql_line = $column-&gt;line $datasrc;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+FS::dbdef::column objects represend columns in tables (see <A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>).
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new</A></STRONG><DD>
+<P>
+Creates a new FS::dbdef_column object.
+
+<DT><STRONG><A NAME="item_name">name</A></STRONG><DD>
+<P>
+Returns or sets the column name.
+
+<DT><STRONG><A NAME="item_type">type</A></STRONG><DD>
+<P>
+Returns or sets the column type.
+
+<DT><STRONG><A NAME="item_null">null</A></STRONG><DD>
+<P>
+Returns or sets the column null flag.
+
+<DT><STRONG>type</STRONG><DD>
+<P>
+Returns or sets the column length.
+
+<DT><STRONG><A NAME="item_line">line [ $datasrc ]</A></STRONG><DD>
+<P>
+Returns an SQL column definition.
+
+<P>
+If passed a DBI <CODE>$datasrc</CODE> specifying <A HREF="../DBD/mysql.html">DBD::mysql</A> or <A HREF="../DBD/Pg.html">DBD::Pg</A>, will use engine-specific syntax.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>, <A HREF="../FS/dbdef.html">FS::dbdef</A>, <EM>DBI</EM>
+
+
+
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: dbdef_column.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/dbdef_index.html b/htdocs/docs/man/FS/dbdef_index.html
new file mode 100644
index 000000000..7a9e5039e
--- /dev/null
+++ b/htdocs/docs/man/FS/dbdef_index.html
@@ -0,0 +1,58 @@
+<HTML>
+<HEAD>
+<TITLE>FS::dbdef_unique.pm - Index object</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::dbdef_unique.pm - Index object
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::dbdef_index;
+</PRE>
+<P>
+<PRE> # see FS::dbdef_colgroup methods
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+FS::dbdef_unique objects represent the (non-unique) indices of a table (<A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>). FS::dbdef_unique inherits from FS::dbdef_colgroup.
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Is this empty subclass needed?
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/dbdef_colgroup.html">FS::dbdef_colgroup</A>, <A HREF="../FS/dbdef_record.html">FS::dbdef_record</A>, <A HREF="../FS/Record.html">FS::Record</A>
+
+
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/dbdef_table.html b/htdocs/docs/man/FS/dbdef_table.html
new file mode 100644
index 000000000..7056b0f9b
--- /dev/null
+++ b/htdocs/docs/man/FS/dbdef_table.html
@@ -0,0 +1,144 @@
+<HTML>
+<HEAD>
+<TITLE>FS::dbdef_table - Table objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::dbdef_table - Table objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::dbdef_table;
+</PRE>
+<P>
+<PRE> $dbdef_table = new FS::dbdef_table (
+ &quot;table_name&quot;,
+ &quot;primary_key&quot;,
+ $FS_dbdef_unique_object,
+ $FS_dbdef_index_object,
+ @FS_dbdef_column_objects,
+ );
+</PRE>
+<P>
+<PRE> $dbdef_table-&gt;addcolumn ( $FS_dbdef_column_object );
+</PRE>
+<P>
+<PRE> $table_name = $dbdef_table-&gt;name;
+ $dbdef_table-&gt;name (&quot;table_name&quot;);
+</PRE>
+<P>
+<PRE> $table_name = $dbdef_table-&gt;primary_keye;
+ $dbdef_table-&gt;primary_key (&quot;primary_key&quot;);
+</PRE>
+<P>
+<PRE> $FS_dbdef_unique_object = $dbdef_table-&gt;unique;
+ $dbdef_table-&gt;unique ( $FS_dbdef_unique_object );
+</PRE>
+<P>
+<PRE> $FS_dbdef_index_object = $dbdef_table-&gt;index;
+ $dbdef_table-&gt;index ( $FS_dbdef_index_object );
+</PRE>
+<P>
+<PRE> @column_names = $dbdef-&gt;columns;
+</PRE>
+<P>
+<PRE> $FS_dbdef_column_object = $dbdef-&gt;column;
+</PRE>
+<P>
+<PRE> @sql_statements = $dbdef-&gt;sql_create_table;
+ @sql_statements = $dbdef-&gt;sql_create_table $datasrc;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+FS::dbdef_table objects represent a single database table.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new</A></STRONG><DD>
+<P>
+Creates a new FS::dbdef_table object.
+
+<DT><STRONG><A NAME="item_addcolumn">addcolumn</A></STRONG><DD>
+<P>
+Adds this FS::dbdef_column object.
+
+<DT><STRONG><A NAME="item_name">name</A></STRONG><DD>
+<P>
+Returns or sets the table name.
+
+<DT><STRONG><A NAME="item_primary_key">primary_key</A></STRONG><DD>
+<P>
+Returns or sets the primary key.
+
+<DT><STRONG><A NAME="item_unique">unique</A></STRONG><DD>
+<P>
+Returns or sets the FS::dbdef_unique object.
+
+<DT><STRONG><A NAME="item_index">index</A></STRONG><DD>
+<P>
+Returns or sets the FS::dbdef_index object.
+
+<DT><STRONG><A NAME="item_columns">columns</A></STRONG><DD>
+<P>
+Returns a list consisting of the names of all columns.
+
+<DT><STRONG><A NAME="item_column">column &quot;column&quot;</A></STRONG><DD>
+<P>
+Returns the column object (see <A HREF="../FS/dbdef_column.html">FS::dbdef_column</A>) for ``column''.
+
+<DT><STRONG><A NAME="item_sql_create_table">sql_create_table [ $datasrc ]</A></STRONG><DD>
+<P>
+Returns an array of SQL statments to create this table.
+
+<P>
+If passed a DBI <CODE>$datasrc</CODE> specifying <A HREF="../DBD/mysql.html">DBD::mysql</A>, will use MySQL-specific syntax. Non-standard syntax for other engines (if
+applicable) may also be supported in the future.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/dbdef.html">FS::dbdef</A>, <A HREF="../FS/dbdef_unique.html">FS::dbdef_unique</A>, <A HREF="../FS/dbdef_index.html">FS::dbdef_index</A>, <A HREF="../FS/dbdef_unique.html">FS::dbdef_unique</A>,
+<EM>DBI</EM>
+
+
+
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: dbdef_table.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/dbdef_unique.html b/htdocs/docs/man/FS/dbdef_unique.html
new file mode 100644
index 000000000..73c885c75
--- /dev/null
+++ b/htdocs/docs/man/FS/dbdef_unique.html
@@ -0,0 +1,58 @@
+<HTML>
+<HEAD>
+<TITLE>FS::dbdef_unique.pm - Unique object</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::dbdef_unique.pm - Unique object
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::dbdef_unique;
+</PRE>
+<P>
+<PRE> # see FS::dbdef_colgroup methods
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+FS::dbdef_unique objects represent the unique indices of a database table (<A HREF="../FS/dbdef_table.html">FS::dbdef_table</A>). FS::dbdef_unique inherits from FS::dbdef_colgroup.
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Is this empty subclass needed?
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/dbdef_colgroup.html">FS::dbdef_colgroup</A>, <A HREF="../FS/dbdef_record.html">FS::dbdef_record</A>, <A HREF="../FS/Record.html">FS::Record</A>
+
+
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/part_pkg.html b/htdocs/docs/man/FS/part_pkg.html
new file mode 100644
index 000000000..e36b5840c
--- /dev/null
+++ b/htdocs/docs/man/FS/part_pkg.html
@@ -0,0 +1,152 @@
+<HTML>
+<HEAD>
+<TITLE>FS::part_pkg - Object methods for part_pkg objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::part_pkg - Object methods for part_pkg objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::part_pkg;
+</PRE>
+<P>
+<PRE> $record = new FS::part_pkg \%hash
+ $record = new FS::part_pkg { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $custom_record = $template_record-&gt;clone;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> @pkg_svc = $record-&gt;pkg_svc;
+</PRE>
+<P>
+<PRE> $svcnum = $record-&gt;svcpart;
+ $svcnum = $record-&gt;svcpart( 'svc_acct' );
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::part_pkg object represents a billing item definition. FS::part_pkg
+inherits from FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_pkgpart">pkgpart - primary key (assigned automatically for new billing item definitions)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_pkg">pkg - Text name of this billing item definition (customer-viewable)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_comment">comment - Text name of this billing item definition (non-customer-viewable)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_setup">setup - Setup fee</A></STRONG><DD>
+<DT><STRONG><A NAME="item_freq">freq - Frequency of recurring fee</A></STRONG><DD>
+<DT><STRONG><A NAME="item_recur">recur - Recurring fee</A></STRONG><DD>
+</DL>
+<P>
+setup and recur are evaluated as Safe perl expressions. You can use numbers
+just as you would normally. More advanced semantics are not yet defined.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new billing item definition. To add the billing item definition
+to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_clone">clone</A></STRONG><DD>
+<P>
+An alternate constructor. Creates a new billing item definition by
+duplicating an existing definition. A new pkgpart is assigned and `(CUSTOM)
+' is prepended to the comment field. To add the billing item definition to
+the database, see
+<A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this billing item definition to the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid billing item definition. If
+there is an error, returns the error, otherwise returns false. Called by
+the insert and replace methods.
+
+<DT><STRONG><A NAME="item_pkg_svc">pkg_svc</A></STRONG><DD>
+<P>
+Returns all FS::pkg_svc objects (see <A HREF="../FS/pkg_svc.html">FS::pkg_svc</A>) for this package definition.
+
+<DT><STRONG><A NAME="item_svcpart">svcpart [ SVCDB ]</A></STRONG><DD>
+<P>
+Returns the svcpart of a single service definition (see <A HREF="../FS/part_svc.html">FS::part_svc</A>) associated with this billing item definition (see <A HREF="../FS/pkg_svc.html">FS::pkg_svc</A>). Returns false if there not exactly one service definition with quantity
+1, or if SVCDB is specified and does not match the svcdb of the service
+definition,
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: part_pkg.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The delete method is unimplemented.
+
+<P>
+setup and recur semantics are not yet defined (and are implemented in
+FS::cust_bill. hmm.).
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>, <A HREF="../FS/type_pkgs.html">FS::type_pkgs</A>, <A HREF="../FS/pkg_svc.html">FS::pkg_svc</A>, <EM>Safe</EM>. schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/part_referral.html b/htdocs/docs/man/FS/part_referral.html
new file mode 100644
index 000000000..b6fd2ce89
--- /dev/null
+++ b/htdocs/docs/man/FS/part_referral.html
@@ -0,0 +1,113 @@
+<HTML>
+<HEAD>
+<TITLE>FS::part_referral - Object methods for part_referral objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::part_referral - Object methods for part_referral objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::part_referral;
+</PRE>
+<P>
+<PRE> $record = new FS::part_referral \%hash
+ $record = new FS::part_referral { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::part_referral represents a referral - where a customer heard of your
+services. This can be used to track the effectiveness of a particular piece
+of advertising, for example. FS::part_referral inherits from FS::Record.
+The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_refnum">refnum - primary key (assigned automatically for new referrals)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_referral">referral - Text name of this referral</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new referral. To add the referral to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this referral to the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid referral. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: part_referral.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The delete method is unimplemented.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_main.html">FS::cust_main</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/part_svc.html b/htdocs/docs/man/FS/part_svc.html
new file mode 100644
index 000000000..fedcbd3bf
--- /dev/null
+++ b/htdocs/docs/man/FS/part_svc.html
@@ -0,0 +1,121 @@
+<HTML>
+<HEAD>
+<TITLE>FS::part_svc - Object methods for part_svc objects</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::part_svc - Object methods for part_svc objects
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::part_svc;
+</PRE>
+<P>
+<PRE> $record = new FS::part_referral \%hash
+ $record = new FS::part_referral { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::part_svc represents a service definition. FS::part_svc inherits from
+FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_svcpart">svcpart - primary key (assigned automatically for new service definitions)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_svc">svc - text name of this service definition</A></STRONG><DD>
+<DT><STRONG><A NAME="item_svcdb">svcdb - table used for this service. See FS::svc_acct,
+FS::svc_domain, and FS::svc_acct_sm, among others.</A></STRONG><DD>
+<DT><STRONG><A NAME="item_svcdb_field">svcdb__field - Default or fixed value for field in svcdb.</A></STRONG><DD>
+<DT><STRONG><A NAME="item_svcdb_field_flag">svcdb__field_flag - defines svcdb__field action: null, `D' for default, or `F' for fixed</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new service definition. To add the service definition to the
+database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this service definition to the database. If there is an error, returns
+the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Currently unimplemented.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid service definition. If there
+is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: part_svc.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+Delete is unimplemented.
+
+<P>
+The list of svc_* tables is hardcoded. When svc_acct_pop is renamed, this
+should be fixed.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/part_pkg.html">FS::part_pkg</A>, <A HREF="../FS/pkg_svc.html">FS::pkg_svc</A>, <A HREF="../FS/cust_svc.html">FS::cust_svc</A>,
+<A HREF="../FS/svc_acct.html">FS::svc_acct</A>, <A HREF="../FS/svc_acct_sm.html">FS::svc_acct_sm</A>, <A HREF="../FS/svc_domain.html">FS::svc_domain</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/pkg_svc.html b/htdocs/docs/man/FS/pkg_svc.html
new file mode 100644
index 000000000..7cd786354
--- /dev/null
+++ b/htdocs/docs/man/FS/pkg_svc.html
@@ -0,0 +1,125 @@
+<HTML>
+<HEAD>
+<TITLE>FS::pkg_svc - Object methods for pkg_svc records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::pkg_svc - Object methods for pkg_svc records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::pkg_svc;
+</PRE>
+<P>
+<PRE> $record = new FS::pkg_svc \%hash;
+ $record = new FS::pkg_svc { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $part_pkg = $record-&gt;part_pkg;
+</PRE>
+<P>
+<PRE> $part_svc = $record-&gt;part_svc;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::pkg_svc record links a billing item definition (see <A HREF="../FS/part_pkg.html">FS::part_pkg</A>) to a service definition (see <A HREF="../FS/part_svc.html">FS::part_svc</A>). FS::pkg_svc inherits from FS::Record. The following fields are currently
+supported:
+
+<DL>
+<DT><STRONG><A NAME="item_pkgpart">pkgpart - Billing item definition (see FS::part_pkg)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_svcpart">svcpart - Service definition (see FS::part_svc)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_quantity">quantity - Quantity of this service definition that this billing item
+definition includes</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Create a new record. To add the record to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid record. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+<DT><STRONG><A NAME="item_part_pkg">part_pkg</A></STRONG><DD>
+<P>
+Returns the FS::part_pkg object (see <A HREF="../FS/part_pkg.html">FS::part_pkg</A>).
+
+<DT><STRONG><A NAME="item_part_svc">part_svc</A></STRONG><DD>
+<P>
+Returns the FS::part_svc object (see <A HREF="../FS/part_svc.html">FS::part_svc</A>).
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: pkg_svc.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/part_pkg.html">FS::part_pkg</A>, <A HREF="../FS/part_svc.html">FS::part_svc</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/svc_Common.html b/htdocs/docs/man/FS/svc_Common.html
new file mode 100644
index 000000000..d8d81a0a7
--- /dev/null
+++ b/htdocs/docs/man/FS/svc_Common.html
@@ -0,0 +1,109 @@
+<HTML>
+<HEAD>
+<TITLE>FS::svc_Common - Object method for all svc_ records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::svc_Common - Object method for all svc_ records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+use FS::svc_Common;
+
+<P>
+<CODE>@ISA</CODE> = <CODE>qw(</CODE> FS::svc_Common );
+
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+FS::svc_Common is intended as a base class for table-specific classes to
+inherit from, i.e. FS::svc_acct. FS::svc_Common inherits from FS::Record.
+
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<P>
+The additional fields pkgnum and svcpart (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A>) should be defined. An FS::cust_svc record will be created and inserted.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this account from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<P>
+The corresponding FS::cust_svc record will be deleted as well.
+
+<DT><STRONG><A NAME="item_setfixed">setfixed</A></STRONG><DD>
+<P>
+Sets any fixed fields for this service (see <A HREF="../FS/part_svc.html">FS::part_svc</A>). If there is an error, returns the error, otherwise returns the
+FS::part_svc object (use <CODE>ref()</CODE> to test the return). Usually
+called by the check method.
+
+<DT><STRONG><A NAME="item_setdefault">setdefault</A></STRONG><DD>
+<P>
+Sets all fields to their defaults (see <A HREF="../FS/part_svc.html">FS::part_svc</A>), overriding their current values. If there is an error, returns the
+error, otherwise returns the FS::part_svc object (use <CODE>ref()</CODE> to
+test the return).
+
+<DT><STRONG><A NAME="item_suspend">suspend</A></STRONG><DD>
+<DT><STRONG><A NAME="item_unsuspend">unsuspend</A></STRONG><DD>
+<DT><STRONG><A NAME="item_cancel">cancel</A></STRONG><DD>
+<P>
+Stubs - return false (no error) so derived classes don't need to define
+these methods. Called by the cancel method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: svc_Common.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The setfixed method return value.
+
+<P>
+The new method should set defaults from part_svc (like the check method
+sets fixed values)?
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/cust_svc.html">FS::cust_svc</A>, <A HREF="../FS/part_svc.html">FS::part_svc</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/svc_acct.html b/htdocs/docs/man/FS/svc_acct.html
new file mode 100644
index 000000000..4b307455e
--- /dev/null
+++ b/htdocs/docs/man/FS/svc_acct.html
@@ -0,0 +1,210 @@
+<HTML>
+<HEAD>
+<TITLE>FS::svc_acct - Object methods for svc_acct records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::svc_acct - Object methods for svc_acct records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::svc_acct;
+</PRE>
+<P>
+<PRE> $record = new FS::svc_acct \%hash;
+ $record = new FS::svc_acct { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;suspend;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;unsuspend;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;cancel;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::svc_acct object represents an account. FS::svc_acct inherits from
+FS::svc_Common. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_svcnum">svcnum - primary key (assigned automatcially for new accounts)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_username">username</A></STRONG><DD>
+<DT><STRONG><A NAME="item__password">_password - generated if blank</A></STRONG><DD>
+<DT><STRONG><A NAME="item_popnum">popnum - Point of presence (see FS::svc_acct_pop)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_uid">uid</A></STRONG><DD>
+<DT><STRONG><A NAME="item_gid">gid</A></STRONG><DD>
+<DT><STRONG><A NAME="item_finger">finger - GECOS</A></STRONG><DD>
+<DT><STRONG><A NAME="item_dir">dir - set automatically if blank (and uid is not)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_shell">shell</A></STRONG><DD>
+<DT><STRONG><A NAME="item_quota">quota - (unimplementd)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_slipip">slipip - IP address</A></STRONG><DD>
+<DT><STRONG><A NAME="item_radius_Radius_Attribute">radius_Radius_Attribute - Radius-Attribute</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new account. To add the account to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this account to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<P>
+The additional fields pkgnum and svcpart (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A>) should be defined. An FS::cust_svc record will be created and inserted.
+
+<P>
+If the configuration value (see <A HREF="../FS/Conf.html">FS::Conf</A>) shellmachine exists, and the username, uid, and dir fields are defined,
+the command
+
+<P>
+<PRE> useradd -d $dir -m -s $shell -u $uid $username
+</PRE>
+<P>
+is executed on shellmachine via ssh. This behaviour can be surpressed by
+setting $FS::svc_acct::nossh_hack true.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this account from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<P>
+The corresponding FS::cust_svc record will be deleted as well.
+
+<P>
+If the configuration value (see <A HREF="../FS/Conf.html">FS::Conf</A>) shellmachine exists, the command:
+
+<P>
+<PRE> userdel $username
+</PRE>
+<P>
+is executed on shellmachine via ssh. This behaviour can be surpressed by
+setting $FS::svc_acct::nossh_hack true.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<P>
+If the configuration value (see <A HREF="../FS/Conf.html">FS::Conf</A>) shellmachine exists, and the dir field has changed, the command:
+
+<P>
+<PRE> [ -d $old_dir ] &amp;&amp; (
+ chmod u+t $old_dir;
+ umask 022;
+ mkdir $new_dir;
+ cd $old_dir;
+ find . -depth -print | cpio -pdm $new_dir;
+ chmod u-t $new_dir;
+ chown -R $uid.$gid $new_dir;
+ rm -rf $old_dir
+ )
+</PRE>
+<P>
+is executed on shellmachine via ssh. This behaviour can be surpressed by
+setting $FS::svc_acct::nossh_hack true.
+
+<DT><STRONG><A NAME="item_suspend">suspend</A></STRONG><DD>
+<P>
+Suspends this account by prefixing *SUSPENDED* to the password. If there is
+an error, returns the error, otherwise returns false.
+
+<P>
+Called by the suspend method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_unsuspend">unsuspend</A></STRONG><DD>
+<P>
+Unsuspends this account by removing *SUSPENDED* from the password. If there
+is an error, returns the error, otherwise returns false.
+
+<P>
+Called by the unsuspend method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_cancel">cancel</A></STRONG><DD>
+<P>
+Just returns false (no error) for now.
+
+<P>
+Called by the cancel method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid service. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+<P>
+Sets any fixed values; see <A HREF="../FS/part_svc.html">FS::part_svc</A>.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: svc_acct.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The remote commands should be configurable.
+
+<P>
+The bits which ssh should fork before doing so.
+
+<P>
+The <CODE>$recref</CODE> stuff in sub check should be cleaned up.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/svc_Common.html">FS::svc_Common</A>, <A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/Conf.html">FS::Conf</A>, <A HREF="../FS/cust_svc.html">FS::cust_svc</A>,
+<A HREF="../FS/part_svc.html">FS::part_svc</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>, <A HREF="../FS/SSH.html">FS::SSH</A>, <EM>ssh</EM>, <A HREF="../FS/svc_acct_pop.html">FS::svc_acct_pop</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/svc_acct_pop.html b/htdocs/docs/man/FS/svc_acct_pop.html
new file mode 100644
index 000000000..0deee2eac
--- /dev/null
+++ b/htdocs/docs/man/FS/svc_acct_pop.html
@@ -0,0 +1,115 @@
+<HTML>
+<HEAD>
+<TITLE>FS::svc_acct_pop - Object methods for svc_acct_pop records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::svc_acct_pop - Object methods for svc_acct_pop records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::svc_acct_pop;
+</PRE>
+<P>
+<PRE> $record = new FS::svc_acct_pop \%hash;
+ $record = new FS::svc_acct_pop { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::svc_acct object represents an point of presence. FS::svc_acct_pop
+inherits from FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_popnum">popnum - primary key (assigned automatically for new accounts)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_city">city</A></STRONG><DD>
+<DT><STRONG><A NAME="item_state">state</A></STRONG><DD>
+<DT><STRONG><A NAME="item_ac">ac - area code</A></STRONG><DD>
+<DT><STRONG><A NAME="item_exch">exch - exchange</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new point of presence (if only it were that easy!). To add the
+point of presence to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this point of presence to the database. If there is an error, returns
+the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Removes this point of presence from the database.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid point of presence. If there
+is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: svc_acct_pop.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+It should be renamed to part_pop.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF=".././FS/svc_acct.html#">the svc_acct manpage</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/svc_acct_sm.html b/htdocs/docs/man/FS/svc_acct_sm.html
new file mode 100644
index 000000000..2b8348544
--- /dev/null
+++ b/htdocs/docs/man/FS/svc_acct_sm.html
@@ -0,0 +1,172 @@
+<HTML>
+<HEAD>
+<TITLE>FS::svc_acct_sm - Object methods for svc_acct_sm records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::svc_acct_sm - Object methods for svc_acct_sm records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::svc_acct_sm;
+</PRE>
+<P>
+<PRE> $record = new FS::svc_acct_sm \%hash;
+ $record = new FS::svc_acct_sm { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;suspend;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;unsuspend;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;cancel;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::svc_acct object represents a virtual mail alias. FS::svc_acct
+inherits from FS::Record. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_svcnum">svcnum - primary key (assigned automatcially for new accounts)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_domsvc">domsvc - svcnum of the virtual domain (see FS::svc_domain)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_domuid">domuid - uid of the target account (see FS::svc_acct)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_domuser">domuser - virtual username</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new virtual mail alias. To add the virtual mail alias to the
+database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this virtual mail alias to the database. If there is an error, returns
+the error, otherwise returns false.
+
+<P>
+The additional fields pkgnum and svcpart (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A>) should be defined. An FS::cust_svc record will be created and inserted.
+
+<P>
+If the configuration values (see <A HREF="../FS/Conf.html">FS::Conf</A>) shellmachine and qmailmachines exist, and domuser is `*' (meaning a
+catch-all mailbox), the command:
+
+<P>
+<PRE> [ -e $dir/.qmail-$qdomain-default ] || {
+ touch $dir/.qmail-$qdomain-default;
+ chown $uid:$gid $dir/.qmail-$qdomain-default;
+ }
+</PRE>
+<P>
+is executed on shellmachine via ssh (see <EM>dot-qmail</EM>). This behaviour can be surpressed by setting $FS::svc_acct_sm::nossh_hack
+true.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this virtual mail alias from the database. If there is an error,
+returns the error, otherwise returns false.
+
+<P>
+The corresponding FS::cust_svc record will be deleted as well.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_suspend">suspend</A></STRONG><DD>
+<P>
+Just returns false (no error) for now.
+
+<P>
+Called by the suspend method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_unsuspend">unsuspend</A></STRONG><DD>
+<P>
+Just returns false (no error) for now.
+
+<P>
+Called by the unsuspend method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_cancel">cancel</A></STRONG><DD>
+<P>
+Just returns false (no error) for now.
+
+<P>
+Called by the cancel method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid virtual mail alias. If there
+is an error, returns the error, otherwise returns false. Called by the
+insert and replace methods.
+
+<P>
+Sets any fixed values; see <A HREF="../FS/part_svc.html">FS::part_svc</A>.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: svc_acct_sm.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+The remote commands should be configurable.
+
+<P>
+The <CODE>$recref</CODE> stuff in sub check should be cleaned up.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/Conf.html">FS::Conf</A>, <A HREF="../FS/cust_svc.html">FS::cust_svc</A>, <A HREF="../FS/part_svc.html">FS::part_svc</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>,
+<A HREF="../FS/svc_acct.html">FS::svc_acct</A>, <A HREF="../FS/svc_domain.html">FS::svc_domain</A>, <A HREF="../FS/SSH.html">FS::SSH</A>, <EM>ssh</EM>, <EM>dot-qmail</EM>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/svc_domain.html b/htdocs/docs/man/FS/svc_domain.html
new file mode 100644
index 000000000..9b5e1a53c
--- /dev/null
+++ b/htdocs/docs/man/FS/svc_domain.html
@@ -0,0 +1,196 @@
+<HTML>
+<HEAD>
+<TITLE>FS::svc_domain - Object methods for svc_domain records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::svc_domain - Object methods for svc_domain records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::svc_domain;
+</PRE>
+<P>
+<PRE> $record = new FS::svc_domain \%hash;
+ $record = new FS::svc_domain { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;suspend;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;unsuspend;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;cancel;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::svc_domain object represents a domain. FS::svc_domain inherits from
+FS::svc_Common. The following fields are currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_svcnum">svcnum - primary key (assigned automatically for new accounts)</A></STRONG><DD>
+<DT><STRONG><A NAME="item_domain">domain</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Creates a new domain. To add the domain to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this domain to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<P>
+The additional fields <EM>pkgnum</EM> and <EM>svcpart</EM> (see <A HREF="../FS/cust_svc.html">FS::cust_svc</A>) should be defined. An FS::cust_svc record will be created and inserted.
+
+<P>
+The additional field <EM>action</EM> should be set to <EM>N</EM> for new domains or <EM>M</EM>
+for transfers.
+
+<P>
+A registration or transfer email will be submitted unless
+$FS::svc_domain::whois_hack is true.
+
+<P>
+The additional field <EM>email</EM> can be used to manually set the admin contact email address on this email.
+Otherwise, the svc_acct records for this package (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>) are searched. If there is exactly one svc_acct record in the same
+package, it is automatically used. Otherwise an error is returned.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this domain from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<P>
+The corresponding FS::cust_svc record will be deleted as well.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_suspend">suspend</A></STRONG><DD>
+<P>
+Just returns false (no error) for now.
+
+<P>
+Called by the suspend method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_unsuspend">unsuspend</A></STRONG><DD>
+<P>
+Just returns false (no error) for now.
+
+<P>
+Called by the unsuspend method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_cancel">cancel</A></STRONG><DD>
+<P>
+Just returns false (no error) for now.
+
+<P>
+Called by the cancel method of FS::cust_pkg (see <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>).
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid domain. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+<P>
+Sets any fixed values; see <A HREF="../FS/part_svc.html">FS::part_svc</A>.
+
+<DT><STRONG><A NAME="item_whois">whois</A></STRONG><DD>
+<P>
+Returns the Net::Whois object corresponding to this domain, or undef if the
+domain is not found in whois.
+
+<P>
+(If $FS::svc_domain::whois_hack is true, returns that in all cases
+instead.)
+
+<DT><STRONG><A NAME="item__whois">_whois</A></STRONG><DD>
+<P>
+Depriciated.
+
+<DT><STRONG><A NAME="item_submit_internic">submit_internic</A></STRONG><DD>
+<P>
+Submits a registration email for this domain.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: svc_domain.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+All BIND/DNS fields should be included (and exported).
+
+<P>
+Delete doesn't send a registration template.
+
+<P>
+All registries should be supported.
+
+<P>
+Should change action to a real field.
+
+<P>
+The <CODE>$recref</CODE> stuff in sub check should be cleaned up.
+
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/svc_Common.html">FS::svc_Common</A>, <A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/Conf.html">FS::Conf</A>, <A HREF="../FS/cust_svc.html">FS::cust_svc</A>,
+<A HREF="../FS/part_svc.html">FS::part_svc</A>, <A HREF="../FS/cust_pkg.html">FS::cust_pkg</A>, <A HREF="../FS/SSH.html">FS::SSH</A>, <A HREF="../Net/Whois.html">Net::Whois</A>, <EM>ssh</EM>,
+<EM>dot-qmail</EM>, schema.html from the base documentation, config.html from the base
+documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/FS/type_pkgs.html b/htdocs/docs/man/FS/type_pkgs.html
new file mode 100644
index 000000000..aa55cce9d
--- /dev/null
+++ b/htdocs/docs/man/FS/type_pkgs.html
@@ -0,0 +1,109 @@
+<HTML>
+<HEAD>
+<TITLE>FS::type_pkgs - Object methods for type_pkgs records</TITLE>
+<LINK REV="made" HREF="mailto:ivan@rootwood.sisd.com">
+</HEAD>
+
+<BODY>
+
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#NAME">NAME</A>
+ <LI><A HREF="#SYNOPSIS">SYNOPSIS</A>
+ <LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
+ <LI><A HREF="#METHODS">METHODS</A>
+ <LI><A HREF="#VERSION">VERSION</A>
+ <LI><A HREF="#BUGS">BUGS</A>
+ <LI><A HREF="#SEE_ALSO">SEE ALSO</A>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<H1><A NAME="NAME">NAME</A></H1>
+<P>
+FS::type_pkgs - Object methods for type_pkgs records
+
+<P>
+<HR>
+<H1><A NAME="SYNOPSIS">SYNOPSIS</A></H1>
+<P>
+<PRE> use FS::type_pkgs;
+</PRE>
+<P>
+<PRE> $record = new FS::type_pkgs \%hash;
+ $record = new FS::type_pkgs { 'column' =&gt; 'value' };
+</PRE>
+<P>
+<PRE> $error = $record-&gt;insert;
+</PRE>
+<P>
+<PRE> $error = $new_record-&gt;replace($old_record);
+</PRE>
+<P>
+<PRE> $error = $record-&gt;delete;
+</PRE>
+<P>
+<PRE> $error = $record-&gt;check;
+</PRE>
+<P>
+<HR>
+<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
+<P>
+An FS::type_pkgs record links an agent type (see <A HREF="../FS/agent_type.html">FS::agent_type</A>) to a billing item definition (see <A HREF="../FS/part_pkg.html">FS::part_pkg</A>). FS::type_pkgs inherits from FS::Record. The following fields are
+currently supported:
+
+<DL>
+<DT><STRONG><A NAME="item_typenum">typenum - Agent type, see FS::agent_type</A></STRONG><DD>
+<DT><STRONG><A NAME="item_pkgpart">pkgpart - Billing item definition, see FS::part_pkg</A></STRONG><DD>
+</DL>
+<P>
+<HR>
+<H1><A NAME="METHODS">METHODS</A></H1>
+<DL>
+<DT><STRONG><A NAME="item_new">new HASHREF</A></STRONG><DD>
+<P>
+Create a new record. To add the record to the database, see <A HREF="#insert">insert</A>.
+
+<DT><STRONG><A NAME="item_insert">insert</A></STRONG><DD>
+<P>
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+<DT><STRONG><A NAME="item_delete">delete</A></STRONG><DD>
+<P>
+Deletes this record from the database. If there is an error, returns the
+error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_replace">replace OLD_RECORD</A></STRONG><DD>
+<P>
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+<DT><STRONG><A NAME="item_check">check</A></STRONG><DD>
+<P>
+Checks all fields to make sure this is a valid record. If there is an
+error, returns the error, otherwise returns false. Called by the insert and
+replace methods.
+
+</DL>
+<P>
+<HR>
+<H1><A NAME="VERSION">VERSION</A></H1>
+<P>
+$Id: type_pkgs.html,v 1.1 1999-08-04 12:13:27 ivan Exp $
+
+<P>
+<HR>
+<H1><A NAME="BUGS">BUGS</A></H1>
+<P>
+<HR>
+<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
+<P>
+<A HREF="../FS/Record.html">FS::Record</A>, <A HREF="../FS/agent_type.html">FS::agent_type</A>, <A HREF="../FS/part_pkgs.html">FS::part_pkgs</A>, schema.html from the base documentation.
+
+</BODY>
+
+</HTML>
diff --git a/htdocs/docs/man/Invoice.txt b/htdocs/docs/man/Invoice.txt
deleted file mode 100644
index 17953d51d..000000000
--- a/htdocs/docs/man/Invoice.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-NAME
- FS::Invoice - Legacy stub
-
-SYNOPSIS
- The functioanlity of FS::invoice has been integrated in
- FS::cust_bill.
-
-HISTORY
- ivan@voicenet.com 97-jun-25 - 27
-
- maybe should be changed to be OO-functions on $cust_bill
- objects? (instead of passing invnum, ugh).
-
- ISA cust_bill and return inovice instead of passing filehandle
- ivan@sisd.com 98-mar-13 (add postscript output!)
-
- close our kid when we're done ivan@sisd.com 98-jun-4
-
- separated code which shuffled data from code which formatted.
- (so i could) fixed past due notices showing up when balance due
- =< 0 return address comes from /var/spool/freeside/conf/address
- ivan@sisd.com 98-jul-2
-
diff --git a/htdocs/docs/man/Record.txt b/htdocs/docs/man/Record.txt
deleted file mode 100644
index 0accb65d1..000000000
--- a/htdocs/docs/man/Record.txt
+++ /dev/null
@@ -1,332 +0,0 @@
-NAME
- FS::Record - Database record objects
-
-SYNOPSIS
- use FS::Record;
- use FS::Record qw(dbh fields hfields qsearch qsearchs dbdef);
-
- $record = new FS::Record 'table', \%hash;
- $record = new FS::Record 'table', { 'column' => 'value', ... };
-
- $record = qsearchs FS::Record 'table', \%hash;
- $record = qsearchs FS::Record 'table', { 'column' => 'value', ... };
- @records = qsearch FS::Record 'table', \%hash;
- @records = qsearch FS::Record 'table', { 'column' => 'value', ... };
-
- $table = $record->table;
- $dbdef_table = $record->dbdef_table;
-
- $value = $record->get('column');
- $value = $record->getfield('column');
- $value = $record->column;
-
- $record->set( 'column' => 'value' );
- $record->setfield( 'column' => 'value' );
- $record->column('value');
-
- %hash = $record->hash;
-
- $hashref = $record->hashref;
-
- $error = $record->add;
-
- $error = $record->del;
-
- $error = $new_record->rep($old_record);
-
- $value = $record->unique('column');
-
- $value = $record->ut_float('column');
- $value = $record->ut_number('column');
- $value = $record->ut_numbern('column');
- $value = $record->ut_money('column');
- $value = $record->ut_text('column');
- $value = $record->ut_textn('column');
- $value = $record->ut_alpha('column');
- $value = $record->ut_alphan('column');
- $value = $record->ut_phonen('column');
- $value = $record->ut_anythingn('column');
-
- $dbdef = reload_dbdef;
- $dbdef = reload_dbdef "/non/standard/filename";
- $dbdef = dbdef;
-
- $quoted_value = _quote($value,'table','field');
-
- #depriciated
- $fields = hfields('table');
- if ( $fields->{Field} ) { # etc.
-
- @fields = fields 'table';
-
-DESCRIPTION
- (Mostly) object-oriented interface to database records. Records
- are currently implemented on top of DBI. FS::Record is intended
- as a base class for table-specific classes to inherit from, i.e.
- FS::cust_main.
-
-METHODS
- new TABLE, HASHREF
- Creates a new record. It doesn't store it in the database,
- though. See the section on "add" for that.
-
- Note that the object stores this hash reference, not a
- distinct copy of the hash it points to. You can ask the
- object for a copy with the *hash* method.
-
- qsearch TABLE, HASHREF
- Searches the database for all records matching (at least)
- the key/value pairs in HASHREF. Returns all the records
- found as FS::Record objects.
-
- qsearchs TABLE, HASHREF
- Searches the database for a record matching (at least) the
- key/value pairs in HASHREF, and returns the record found as
- an FS::Record object. If more than one record matches, it
- carps but returns the first. If this happens, you either
- made a logic error in asking for a single item, or your data
- is corrupted.
-
- table
- Returns the table name.
-
- dbdef_table
- Returns the FS::dbdef_table object for the table.
-
- get, getfield COLUMN
- Returns the value of the column/field/key COLUMN.
-
- set, setfield COLUMN, VALUE
- Sets the value of the column/field/key COLUMN to VALUE.
- Returns VALUE.
-
- AUTLOADED METHODS
- $record->column is a synonym for $record->get('column');
-
- $record->column('value') is a synonym for $record-
- >set('column','value');
-
- hash
- Returns a list of the column/value pairs, usually for
- assigning to a new hash.
-
- To make a distinct duplicate of an FS::Record object, you
- can do:
-
- $new = new FS::Record ( $old->table, { $old->hash } );
-
- hashref
- Returns a reference to the column/value hash.
-
- add Adds this record to the database. If there is an error, returns
- the error, otherwise returns false.
-
- del Delete this record from the database. If there is an error,
- returns the error, otherwise returns false.
-
- rep OLD_RECORD
- Replace the OLD_RECORD with this one in the database. If
- there is an error, returns the error, otherwise returns
- false.
-
- unique COLUMN
- Replaces COLUMN in record with a unique number. Called by
- the add method on primary keys and single-field unique
- columns (see the FS::dbdef_table manpage). Returns the new
- value.
-
- ut_float COLUMN
- Check/untaint floating point numeric data: 1.1, 1, 1.1e10,
- 1e10. May not be null. If there is an error, returns the
- error, otherwise returns false.
-
- ut_number COLUMN
- Check/untaint simple numeric data (whole numbers). May not
- be null. If there is an error, returns the error, otherwise
- returns false.
-
- ut_numbern COLUMN
- Check/untaint simple numeric data (whole numbers). May be
- null. If there is an error, returns the error, otherwise
- returns false.
-
- ut_money COLUMN
- Check/untaint monetary numbers. May be negative. Set to 0 if
- null. If there is an error, returns the error, otherwise
- returns false.
-
- ut_text COLUMN
- Check/untaint text. Alphanumerics, spaces, and the following
- punctuation symbols are currently permitted: ! @ # $ % & ( )
- - + ; : ' " , . ? / May not be null. If there is an error,
- returns the error, otherwise returns false.
-
- ut_textn COLUMN
- Check/untaint text. Alphanumerics, spaces, and the following
- punctuation symbols are currently permitted: ! @ # $ % & ( )
- - + ; : ' " , . ? / May be null. If there is an error,
- returns the error, otherwise returns false.
-
- ut_alpha COLUMN
- Check/untaint alphanumeric strings (no spaces). May not be
- null. If there is an error, returns the error, otherwise
- returns false.
-
- ut_alpha COLUMN
- Check/untaint alphanumeric strings (no spaces). May be null.
- If there is an error, returns the error, otherwise returns
- false.
-
- ut_phonen COLUMN
- Check/untaint phone numbers. May be null. If there is an
- error, returns the error, otherwise returns false.
-
- ut_anything COLUMN
- Untaints arbitrary data. Be careful.
-
-SUBROUTINES
- reload_dbdef([FILENAME])
- Load a database definition (see the FS::dbdef manpage),
- optionally from a non-default filename. This command is
- executed at startup unless *$FS::Record::setup_hack* is
- true. Returns a FS::dbdef object.
-
- dbdef Returns the current database definition. See the FS::dbdef
- manpage.
-
- _quote VALUE, TABLE, COLUMN
- This is an internal function used to construct SQL
- statements. It returns VALUE DBI-quoted (see the section
- on "quote" in the DBI manpage) unless VALUE is a number
- and the column type (see the dbdef_column manpage) does
- not end in `char' or `binary'.
-
- hfields TABLE
- This is depriciated. Don't use it.
-
- It returns a hash-type list with the fields of this
- record's table set true.
-
- fields TABLE
- This returns a list of the columns in this record's
- table (See the dbdef_table manpage).
-
-BUGS
- This module should probably be renamed, since much of the
- functionality is of general use. It is not completely unlike
- Adapter::DBI (see below).
-
- Exported qsearch and qsearchs should be depriciated in favor
- of method calls (against an FS::Record object like the old
- search and searchs that qsearch and qsearchs were on top
- of.)
-
- The whole fields / hfields mess should be removed.
-
- The various WHERE clauses should be subroutined.
-
- table string should be depriciated in favor of
- FS::dbdef_table.
-
- No doubt we could benefit from a Tied hash. Documenting how
- exists / defined true maps to the database (and WHERE
- clauses) would also help.
-
- The ut_ methods should ask the dbdef for a default length.
-
- ut_sqltype (like ut_varchar) should all be defined
-
- A fallback check method should be provided with uses the
- dbdef.
-
- The ut_money method assumes money has two decimal digits.
-
- The Pg money kludge in the new method only strips `$'.
-
- The ut_phonen method assumes US-style phone numbers.
-
- The _quote function should probably use ut_float instead of
- a regex.
-
- All the subroutines probably should be methods, here or
- elsewhere.
-
-SEE ALSO
- the FS::dbdef manpage, the FS::UID manpage, the DBI manpage
-
- Adapter::DBI from Ch. 11 of Advanced Perl Programming by
- Sriram Srinivasan.
-
-HISTORY
- ivan@voicenet.com 97-jun-2 - 9, 19, 25, 27, 30
-
- DBI version ivan@sisd.com 97-nov-8 - 12
-
- cleaned up, added autoloaded $self->any_field calls, moved
- DBI login stuff to FS::UID ivan@sisd.com 97-nov-21-23
-
- since AUTO_INCREMENT is MySQL specific, use my own unique
- number generator (again) ivan@sisd.com 97-dec-4
-
- untaint $user in unique (web demo hack...bah) make unique
- skip multiple-field unique's from dbdef ivan@sisd.com 97-
- dec-11
-
- merge with FS::Search, which after all was just alternate
- constructors for FS::Record objects. Makes lots of things
- cleaner. :) ivan@sisd.com 97-dec-13
-
- use FS::dbdef::primary key in replace searches, hopefully
- for all practical purposes the string/number problem in SQL
- statements should be gone? (SQL bites) ivan@sisd.com 98-jan-
- 20
-
- Put all SQL statments in $statment before we $sth=$dbh-
- >prepare( them, for debugging reasons (warn $statement)
- ivan@sisd.com 98-feb-19
-
- (sigh)... use dbdef type (char, etc.) instead of a regex to
- decide what to quote in _quote (more sillines...) SQL bites.
- ivan@sisd.com 98-feb-20
-
- more friendly error messages ivan@sisd.com 98-mar-13
-
- Added import of datasrc from FS::UID to allow Pg6.3 to work
- Added code to right-trim strings read from Pg6.3 databases
- Modified 'add' to only insert fields that actually have data
- Added ut_float to handle floating point numbers (for sales
- tax). Pg6.3 does not have a "SHOW FIELDS" statement, so I
- faked it 8). bmccane@maxbaud.net 98-apr-3
-
- commented out Pg wrapper around `` Modified 'add' to only
- insert fields that actually have data '' ivan@sisd.com 98-
- apr-16
-
- dbdef usage changes ivan@sisd.com 98-jun-1
-
- sub fields now asks dbdef, not database ivan@sisd.com 98-
- jun-2
-
- added debugging method ->_dump ivan@sisd.com 98-jun-16
-
- use FS::dbdef::primary key in delete searches as well as
- replace searches (SQL still bites) ivan@sisd.com 98-jun-22
-
- sub dbdef_table ivan@sisd.com 98-jun-28
-
- removed Pg wrapper around `` Modified 'add' to only insert
- fields that actually have data '' ivan@sisd.com 98-jul-14
-
- sub fields croaks on errors ivan@sisd.com 98-jul-17
-
- $rc eq '0E0' doesn't mean we couldn't delete for all rdbmss
- ivan@sisd.com 98-jul-18
-
- commented out code to right-trim strings read from Pg6.3
- databases; ChopBlanks is in UID.pm ivan@sisd.com 98-aug-16
-
- added code (with Pg wrapper) to deal with Pg money fields
- ivan@sisd.com 98-aug-18
-
- added pod documentation ivan@sisd.com 98-sep-6
-
diff --git a/htdocs/docs/man/SSH.txt b/htdocs/docs/man/SSH.txt
deleted file mode 100644
index b6d205b55..000000000
--- a/htdocs/docs/man/SSH.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-NAME
- FS::SSH - Subroutines to call ssh and scp
-
-SYNOPSIS
- use FS::SSH qw(ssh scp issh iscp sshopen2 sshopen3);
-
- ssh($host, $command);
-
- issh($host, $command);
-
- scp($source, $destination);
-
- iscp($source, $destination);
-
- sshopen2($host, $reader, $writer, $command);
-
- sshopen3($host, $reader, $writer, $error, $command);
-
-DESCRIPTION
- Simple wrappers around ssh and scp commands.
-
-SUBROUTINES
- ssh HOST, COMMAND
- Calls ssh in batch mode.
-
- issh HOST, COMMAND
- Prints the ssh command to be executed, waits for the user to
- confirm, and (optionally) executes the command.
-
- scp SOURCE, DESTINATION
- Calls scp in batch mode.
-
- iscp SOURCE, DESTINATION
- Prints the scp command to be executed, waits for the user to
- confirm, and (optionally) executes the command.
-
- sshopen2 HOST, READER, WRITER, COMMAND
- Connects the supplied filehandles to the ssh process (in
- batch mode).
-
- sshopen3 HOST, WRITER, READER, ERROR, COMMAND
- Connects the supplied filehandles to the ssh process (in
- batch mode).
-
-BUGS
- Not OO.
-
- scp stuff should transparantly use rsync-over-ssh instead.
-
-SEE ALSO
- the ssh manpage, the scp manpage, the IPC::Open2 manpage,
- the IPC::Open3 manpage
-
-HISTORY
- ivan@voicenet.com 97-jul-17
-
- added sshopen2 and sshopen3 ivan@sisd.com 98-mar-9
-
- added iscp ivan@sisd.com 98-jul-25 now iscp asks y/n, issh
- and took out path ivan@sisd.com 98-jul-30
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/UID.txt b/htdocs/docs/man/UID.txt
deleted file mode 100644
index bf9f6b4bd..000000000
--- a/htdocs/docs/man/UID.txt
+++ /dev/null
@@ -1,79 +0,0 @@
-NAME
- FS::UID - Subroutines for database login and assorted other
- stuff
-
-SYNOPSIS
- use FS::UID qw(adminsuidsetup cgisuidsetup dbh datasrc getotaker
- checkeuid checkruid swapuid);
-
- adminsuidsetup;
-
- $cgi = new CGI::Base;
- $cgi->get;
- $dbh = cgisuidsetup($cgi);
-
- $dbh = dbh;
-
- $datasrc = datasrc;
-
-DESCRIPTION
- Provides a hodgepodge of subroutines.
-
-SUBROUTINES
- adminsuidsetup
- Cleans the environment. Make sure the script is running as
- freeside, or setuid freeside. Opens a connection to the
- database. Swaps real and effective UIDs. Returns the DBI
- database handle (usually you don't need this).
-
- dbh Returns the DBI database handle.
-
- datasrc
- Returns the DBI data source.
-
- getotaker
- Returns the current Freeside user. Currently that means the
- CGI REMOTE_USER, or 'freeside'.
-
- checkeuid
- Returns true if effective UID is that of the freeside user.
-
- checkruid
- Returns true if the real UID is that of the freeside user.
-
- swapuid
- Swaps real and effective UIDs.
-
-BUGS
- Not OO.
-
- No capabilities yet. When mod_perl and Authen::DBI are
- implemented, cgisuidsetup will go away as well.
-
-SEE ALSO
- the FS::Record manpage, the CGI::Base manpage, the DBI manpage
-
-HISTORY
- ivan@voicenet.com 97-jun-4 - 9 untaint otaker ivan@voicenet.com
- 97-jul-7
-
- generalize and auto-get uid (getotaker still needs to be db'ed)
- ivan@sisd.com 97-nov-10
-
- &cgisuidsetup logs into database. other cleaning. ivan@sisd.com
- 97-nov-22,23
-
- &adminsuidsetup logs into database with otaker='freeside' (for
- automated tasks like billing) ivan@sisd.com 97-dec-13
-
- added sub datasrc for fs-setup ivan@sisd.com 98-feb-21
-
- datasrc, user and pass now come from conf/secrets ivan@sisd.com
- 98-jun-28
-
- added ChopBlanks to DBI call (see man DBI) ivan@sisd.com 98-aug-
- 16
-
- pod, use FS::Conf, implemented cgisuidsetup as adminsuidsetup,
- inlined suidsetup ivan@sisd.com 98-sep-12
-
diff --git a/htdocs/docs/man/agent.txt b/htdocs/docs/man/agent.txt
deleted file mode 100644
index b0317f6f7..000000000
--- a/htdocs/docs/man/agent.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-NAME
- FS::agent - Object methods for agent records
-
-SYNOPSIS
- use FS::agent;
-
- $record = create FS::agent \%hash;
- $record = create FS::agent { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::agent object represents an agent. Every customer has an
- agent. Agents can be used to track things like resellers or
- salespeople. FS::agent inherits from FS::Record. The following
- fields are currently supported:
-
- agemtnum - primary key (assigned automatically for new agents)
- agent - Text name of this agent
- typenum - Agent type. See the FS::agent_type manpage
- prog - For future use.
- freq - For future use.
-METHODS
- create HASHREF
- Creates a new agent. To add the agent to the database, see
- the section on "insert".
-
- insert
- Adds this agent to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Deletes this agent from the database. Only agents with no
- customers can be deleted. If there is an error, returns the
- error, otherwise returns false.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid agent. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
-SEE ALSO
- the FS::Record manpage, the FS::agent_type manpage, the
- FS::cust_main manpage, schema.html from the base documentation.
-
-HISTORY
- Class dealing with agent (resellers)
-
- ivan@sisd.com 97-nov-13, 97-dec-10
-
- pod, added check in ->delete ivan@sisd.com 98-sep-22
-
diff --git a/htdocs/docs/man/agent_type.txt b/htdocs/docs/man/agent_type.txt
deleted file mode 100644
index ea1edec0c..000000000
--- a/htdocs/docs/man/agent_type.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-NAME
- FS::agent_type - Object methods for agent_type records
-
-SYNOPSIS
- use FS::agent_type;
-
- $record = create FS::agent_type \%hash;
- $record = create FS::agent_type { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::agent_type object represents an agent type. Every agent
- (see the FS::agent manpage) has an agent type. Agent types
- define which packages (see the FS::part_pkg manpage) may be
- purchased by customers (see the FS::cust_main manpage), via
- FS::type_pkgs records (see the FS::type_pkgs manpage).
- FS::agent_type inherits from FS::Record. The following fields
- are currently supported:
-
- typenum - primary key (assigned automatically for new agent types)
- atype - Text name of this agent type
-METHODS
- create HASHREF
- Creates a new agent type. To add the agent type to the
- database, see the section on "insert".
-
- insert
- Adds this agent type to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Deletes this agent type from the database. Only agent types
- with no agents can be deleted. If there is an error, returns
- the error, otherwise returns false.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid agent type.
- If there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
-SEE ALSO
- the FS::Record manpage, the FS::agent manpage, the FS::type_pkgs
- manpage, the FS::cust_main manpage, the FS::part_pkg manpage,
- schema.html from the base documentation.
-
-HISTORY
- Class for the different sets of allowable packages you can
- assign to an agent.
-
- ivan@sisd.com 97-nov-13
-
- ut_ FS::Record methods ivan@sisd.com 97-dec-10
-
- Changed 'type' to 'atype' because Pg6.3 reserves the type word
- bmccane@maxbaud.net 98-apr-3
-
- pod, added check in delete ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/cust_bill.txt b/htdocs/docs/man/cust_bill.txt
deleted file mode 100644
index 9762dd3ca..000000000
--- a/htdocs/docs/man/cust_bill.txt
+++ /dev/null
@@ -1,140 +0,0 @@
-NAME
- FS::cust_bill - Object methods for cust_bill records
-
-SYNOPSIS
- use FS::cust_bill;
-
- $record = create FS::cust_bill \%hash;
- $record = create FS::cust_bill { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
- ( $total_previous_balance, @previous_cust_bill ) = $record->previous;
-
- @cust_bill_pkg_objects = $cust_bill->cust_bill_pkg;
-
- ( $total_previous_credits, @previous_cust_credit ) = $record->cust_credit;
-
- @cust_pay_objects = $cust_bill->cust_pay;
-
- @lines = $cust_bill->print_text;
- @lines = $cust_bill->print_text $time;
-
-DESCRIPTION
- An FS::cust_bill object represents an invoice. FS::cust_bill
- inherits from FS::Record. The following fields are currently
- supported:
-
- invnum - primary key (assigned automatically for new invoices)
- custnum - customer (see the FS::cust_main manpage)
- _date - specified as a UNIX timestamp; see the section on "time" in the perlfunc manpage. Also see
- the Time::Local manpage and the Date::Parse manpage for conversion functions.
- charged - amount of this invoice
- owed - amount still outstanding on this invoice, which is charged minus
- all payments (see the FS::cust_pay manpage).
- printed - how many times this invoice has been printed automatically
- (see the section on "collect" in the FS::cust_main manpage).
-METHODS
- create HASHREF
- Creates a new invoice. To add the invoice to the database,
- see the section on "insert". Invoices are normally created
- by calling the bill method of a customer object (see the
- FS::cust_main manpage).
-
- insert
- Adds this invoice to the database ("Posts" the invoice). If
- there is an error, returns the error, otherwise returns
- false.
-
- When adding new invoices, owed must be charged (or null, in
- which case it is automatically set to charged).
-
- delete
- Currently unimplemented. I don't remove invoices because
- there would then be no record you ever posted this invoice
- (which is bad, no?)
-
- replace OLD_RECORD
- Replaces the OLD_RECORD with this one in the database. If
- there is an error, returns the error, otherwise returns
- false.
-
- Only owed and printed may be changed. Owed is normally
- updated by creating and inserting a payment (see the
- FS::cust_pay manpage). Printed is normally updated by
- calling the collect method of a customer object (see the
- FS::cust_main manpage).
-
- check
- Checks all fields to make sure this is a valid invoice. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
- previous
- Returns a list consisting of the total previous balance for
- this customer, followed by the previous outstanding invoices
- (as FS::cust_bill objects also).
-
- cust_bill_pkg
- Returns the line items (see the FS::cust_bill_pkg manpage)
- for this invoice.
-
- cust_credit
- Returns a list consisting of the total previous credited
- (see the FS::cust_credit manpage) for this customer,
- followed by the previous outstanding credits
- (FS::cust_credit objects).
-
- cust_pay
- Returns all payments (see the FS::cust_pay manpage) for this
- invoice.
-
- print_text [TIME];
- Returns an ASCII invoice, as a list of lines.
-
- TIME an optional value used to control the printing of
- overdue messages. The default is now. It isn't the date of
- the invoice; that's the `_date' field. It is specified as a
- UNIX timestamp; see the section on "time" in the perlfunc
- manpage. Also see the Time::Local manpage and the
- Date::Parse manpage for conversion functions.
-
-BUGS
- The delete method.
-
- It doesn't properly override FS::Record yet.
-
- print_text formatting (and some logic :/) is in source as a
- format declaration, which needs to be slurped in from a file.
- the fork is rather kludgy as well. It could be cleaned with
- swrite from man perlform, and the picture could be put in a
- /var/spool/freeside/conf file. Also number of lines ($=).
-
- missing print_ps for a nice postscript copy (maybe HylaFAX-
- cover-page-style or something similar so the look can be
- completely customized?)
-
- There is an off-by-one error in print_text which causes a visual
- error: "Page 1 of 2" printed on some single-page invoices?
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_main manpage, the
- FS::cust_pay manpage, the FS::cust_bill_pkg manpage, the
- FS::cust_credit manpage, schema.html from the base
- documentation.
-
-HISTORY
- ivan@voicenet.com 97-jul-1
-
- small fix for new API ivan@sisd.com 98-mar-14
-
- charges can be negative ivan@sisd.com 98-jul-13
-
- pod, ingegrate with FS::Invoice ivan@sisd.com 98-sep-20
-
diff --git a/htdocs/docs/man/cust_bill_pkg.txt b/htdocs/docs/man/cust_bill_pkg.txt
deleted file mode 100644
index 1ca4b8cca..000000000
--- a/htdocs/docs/man/cust_bill_pkg.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-NAME
- FS::cust_bill_pkg - Object methods for cust_bill_pkg records
-
-SYNOPSIS
- use FS::cust_bill_pkg;
-
- $record = create FS::cust_bill_pkg \%hash;
- $record = create FS::cust_bill_pkg { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::cust_bill_pkg object represents an invoice line item.
- FS::cust_bill_pkg inherits from FS::Record. The following fields
- are currently supported:
-
- invnum - invoice (see the FS::cust_bill manpage)
- pkgnum - package (see the FS::cust_pkg manpage)
- setup - setup fee
- recur - recurring fee
- sdate - starting date of recurring fee
- edate - ending date of recurring fee
- sdate and edate are specified as UNIX timestamps; see the
- section on "time" in the perlfunc manpage. Also see the
- Time::Local manpage and the Date::Parse manpage for conversion
- functions.
-
-METHODS
- create HASHREF
- Creates a new line item. To add the line item to the
- database, see the section on "insert". Line items are
- normally created by calling the bill method of a customer
- object (see the FS::cust_main manpage).
-
- insert
- Adds this line item to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Currently unimplemented. I don't remove line items because
- there would then be no record the items ever existed (which
- is bad, no?)
-
- replace OLD_RECORD
- Currently unimplemented. This would be even more of an
- accounting nightmare than deleteing the items. Just don't do
- it.
-
- check
- Checks all fields to make sure this is a valid line item. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert method.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_bill manpage, the
- FS::cust_pkg manpage, the FS::cust_main manpage, schema.html
- from the base documentation.
-
-HISTORY
- ivan@sisd.com 98-mar-13
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/cust_credit.txt b/htdocs/docs/man/cust_credit.txt
deleted file mode 100644
index 84591ee81..000000000
--- a/htdocs/docs/man/cust_credit.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-NAME
- FS::cust_credit - Object methods for cust_credit records
-
-SYNOPSIS
- use FS::cust_credit;
-
- $record = create FS::cust_credit \%hash;
- $record = create FS::cust_credit { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::cust_credit object represents a credit. FS::cust_credit
- inherits from FS::Record. The following fields are currently
- supported:
-
- crednum - primary key (assigned automatically for new credits)
- custnum - customer (see the FS::cust_main manpage)
- amount - amount of the credit
- credited - how much of this credit that is still outstanding, which is
- amount minus all refunds (see the FS::cust_refund manpage).
- _date - specified as a UNIX timestamp; see the section on "time" in the perlfunc manpage. Also see
- the Time::Local manpage and the Date::Parse manpage for conversion functions.
- otaker - order taker (assigned automatically, see the FS::UID manpage)
- reason - text
-METHODS
- create HASHREF
- Creates a new credit. To add the credit to the database, see
- the section on "insert".
-
- insert
- Adds this credit to the database ("Posts" the credit). If
- there is an error, returns the error, otherwise returns
- false.
-
- When adding new invoices, credited must be amount (or null,
- in which case it is automatically set to amount).
-
- delete
- Currently unimplemented.
-
- replace OLD_RECORD
- Replaces the OLD_RECORD with this one in the database. If
- there is an error, returns the error, otherwise returns
- false.
-
- Only credited may be changed. Credited is normally updated
- by creating and inserting a refund (see the FS::cust_refund
- manpage).
-
- check
- Checks all fields to make sure this is a valid credit. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
-BUGS
- The delete method.
-
- It doesn't properly override FS::Record yet.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_refund manpage, the
- FS::cust_bill manpage, schema.html from the base documentation.
-
-HISTORY
- ivan@sisd.com 98-mar-17
-
- pod, otaker from FS::UID ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/cust_main.txt b/htdocs/docs/man/cust_main.txt
deleted file mode 100644
index df7848744..000000000
--- a/htdocs/docs/man/cust_main.txt
+++ /dev/null
@@ -1,200 +0,0 @@
-NAME
- FS::cust_main - Object methods for cust_main records
-
-SYNOPSIS
- use FS::cust_main;
-
- $record = create FS::cust_main \%hash;
- $record = create FS::cust_main { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
- @cust_pkg = $record->all_pkgs;
-
- @cust_pkg = $record->ncancelled_pkgs;
-
- $error = $record->bill;
- $error = $record->bill %options;
- $error = $record->bill 'time' => $time;
-
- $error = $record->collect;
- $error = $record->collect %options;
- $error = $record->collect 'invoice_time' => $time,
- 'batch_card' => 'yes',
- 'report_badcard' => 'yes',
- ;
-
-DESCRIPTION
- An FS::cust_main object represents a customer. FS::cust_main
- inherits from FS::Record. The following fields are currently
- supported:
-
- custnum - primary key (assigned automatically for new customers)
- agentnum - agent (see the FS::agent manpage)
- refnum - referral (see the FS::part_referral manpage)
- first - name
- last - name
- ss - social security number (optional)
- company - (optional)
- address1
- address2 - (optional)
- city
- county - (optional, see the FS::cust_main_county manpage)
- state - (see the FS::cust_main_county manpage)
- zip
- country - (see the FS::cust_main_county manpage)
- daytime - phone (optional)
- night - phone (optional)
- payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)
- payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)
- paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy
- payname - name on card or billing name
- tax - tax exempt, empty or `Y'
- otaker - order taker (assigned automatically, see the FS::UID manpage)
-METHODS
- create HASHREF
- Creates a new customer. To add the customer to the database,
- see the section on "insert".
-
- Note that this stores the hash reference, not a distinct
- copy of the hash it points to. You can ask the object for a
- copy with the *hash* method.
-
- insert
- Adds this customer to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Currently unimplemented. Maybe cancel all of this customer's
- packages (cust_pkg)?
-
- I don't remove the customer record in the database because
- there would then be no record the customer ever existed
- (which is bad, no?)
-
- replace OLD_RECORD
- Replaces the OLD_RECORD with this one in the database. If
- there is an error, returns the error, otherwise returns
- false.
-
- check
- Checks all fields to make sure this is a valid customer
- record. If there is an error, returns the error, otherwise
- returns false. Called by the insert and repalce methods.
-
- all_pkgs
- Returns all packages (see the FS::cust_pkg manpage) for this
- customer.
-
- ncancelled_pkgs
- Returns all non-cancelled packages (see the FS::cust_pkg
- manpage) for this customer.
-
- bill OPTIONS
- Generates invoices (see the FS::cust_bill manpage) for this
- customer. Usually used in conjunction with the collect
- method.
-
- 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 the section on "time" in the perlfunc
- manpage). Also see the Time::Local manpage and the
- Date::Parse manpage for conversion functions.
-
- If there is an error, returns the error, otherwise returns
- false.
-
- collect OPTIONS
- (Attempt to) collect money for this customer's outstanding
- invoices (see the FS::cust_bill manpage). Usually used after
- the bill method.
-
- Depending on the value of `payby', this may print an invoice
- (`BILL'), charge a credit card (`CARD'), or just add any
- necessary (pseudo-)payment (`COMP').
-
- If there is an error, returns the error, otherwise returns
- false.
-
- Currently available options are:
-
- invoice_time - Use this time when deciding when to print
- invoices and late notices on those invoices. The default is
- now. It is specified as a UNIX timestamp; see the section on
- "time" in the perlfunc manpage). Also see the Time::Local
- manpage and the Date::Parse manpage for conversion
- functions.
-
- batch_card - Set this true to batch cards (see the
- cust_pay_batch manpage). By default, cards are processed
- immediately, which will generate an error if CyberCash is
- not installed.
-
- report_badcard - Set this true if you want bad card
- transactions to return an error. By default, they don't.
-
- total_owed
- Returns the total owed for this customer on all invoices
- (see the FS::cust_bill manpage).
-
- total_credited
- Returns the total credits (see the FS::cust_credit manpage)
- for this customer.
-
- balance
- Returns the balance for this customer (total owed minus
- total credited).
-
-BUGS
- The delete method.
-
- It doesn't properly override FS::Record yet.
-
- hfields should be removed.
-
- Bill and collect options should probably be passed as references
- instead of a list.
-
- CyberCash v2 forces us to define some variables in package main.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_pkg manpage, the
- FS::cust_bill manpage, the FS::cust_credit manpage the
- FS::cust_pay_batch manpage, the FS::agent manpage, the
- FS::part_referral manpage, the FS::cust_main_county manpage, the
- FS::UID manpage, schema.html from the base documentation.
-
-HISTORY
- ivan@voicenet.com 97-jul-28
-
- Changed to standard Business::CreditCard no more TableUtil
- EXPORT_OK FS::Record's hfields removed unique calls and locking
- (not needed here now) wrapped the (now) optional fields in if
- statements in sub check (notyetdone!) ivan@sisd.com 97-nov-12
-
- updated paydate with SQL-type date info ivan@sisd.com 98-mar-5
-
- Added export of datasrc from UID.pm for Pg6.3 changed 'day' to
- 'daytime' because Pg6.3 reserves the day word
- bmccane@maxbaud.net 98-apr-3
-
- in ->create, s/svc_acct/cust_main/, now it should actually
- eliminate the warnings it was meant to ivan@sisd.com 98-jul-16
-
- don't require a phone number and allow '/' in company names
- ivan@sisd.com 98-jul-18
-
- use ut_ and rewrite &check, &*_pkgs ivan@sisd.com 98-sep-5
-
- pod, merge with FS::Bill (about time!), total_owed,
- total_credited and balance methods, cleaned collect method,
- source modifications no longer necessary to enable cybercash,
- cybercash v3 support, don't need to import
- FS::UID::{datasrc,checkruid} ivan@sisd.com 98-sep-19-21
-
diff --git a/htdocs/docs/man/cust_main_county.txt b/htdocs/docs/man/cust_main_county.txt
deleted file mode 100644
index 8e99397cc..000000000
--- a/htdocs/docs/man/cust_main_county.txt
+++ /dev/null
@@ -1,67 +0,0 @@
-NAME
- FS::cust_main_county - Object methods for cust_main_county
- objects
-
-SYNOPSIS
- use FS::cust_main_county;
-
- $record = create FS::cust_main_county \%hash;
- $record = create FS::cust_main_county { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::cust_main_county object represents a tax rate, defined by
- locale. FS::cust_main_county inherits from FS::Record. The
- following fields are currently supported:
-
- taxnum - primary key (assigned automatically for new tax rates)
- state
- county
- tax - percentage
-METHODS
- create HASHREF
- Creates a new tax rate. To add the tax rate to the database,
- see the section on "insert".
-
- insert
- Adds this tax rate to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Deletes this tax rate from the database. If there is an
- error, returns the error, otherwise returns false.
-
- replace OLD_RECORD
- Replaces the OLD_RECORD with this one in the database. If
- there is an error, returns the error, otherwise returns
- false.
-
- check
- Checks all fields to make sure this is a valid tax rate. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- A country field (and possibly a currency field) should be added.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_main manpage, the
- FS::cust_bill manpage, schema.html from the base documentation.
-
-HISTORY
- ivan@voicenet.com 97-dec-16
-
- Changed check for 'tax' to use the new ut_float subroutine
- bmccane@maxbaud.net 98-apr-3
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/cust_pay.txt b/htdocs/docs/man/cust_pay.txt
deleted file mode 100644
index 9f28d0822..000000000
--- a/htdocs/docs/man/cust_pay.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-NAME
- FS::cust_pay - Object methods for cust_pay objects
-
-SYNOPSIS
- use FS::cust_pay;
-
- $record = create FS::cust_pay \%hash;
- $record = create FS::cust_pay { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::cust_pay object represents a payment. FS::cust_pay
- inherits from FS::Record. The following fields are currently
- supported:
-
- paynum - primary key (assigned automatically for new payments)
- invnum - Invoice (see the FS::cust_bill manpage)
- paid - Amount of this payment
- _date - specified as a UNIX timestamp; see the section on "time" in the perlfunc manpage. Also see
- the Time::Local manpage and the Date::Parse manpage for conversion functions.
- payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)
- payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)
- paybatch - text field for tracking card processing
-METHODS
- create HASHREF
- Creates a new payment. To add the payment to the databse,
- see the section on "insert".
-
- insert
- Adds this payment to the databse, and updates the invoice
- (see the FS::cust_bill manpage).
-
- delete
- Currently unimplemented (accounting reasons).
-
- replace OLD_RECORD
- Currently unimplemented (accounting reasons).
-
- check
- Checks all fields to make sure this is a valid payment. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert method.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- Delete and replace methods.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_bill manpage, schema.html
- from the base documentation.
-
-HISTORY
- ivan@voicenet.com 97-jul-1 - 25 - 29
-
- new api ivan@sisd.com 98-mar-13
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/cust_pkg.txt b/htdocs/docs/man/cust_pkg.txt
deleted file mode 100644
index 5409083d8..000000000
--- a/htdocs/docs/man/cust_pkg.txt
+++ /dev/null
@@ -1,150 +0,0 @@
-NAME
- FS::cust_pkg - Object methods for cust_pkg objects
-
-SYNOPSIS
- use FS::cust_pkg;
-
- $record = create FS::cust_pkg \%hash;
- $record = create FS::cust_pkg { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
- $error = $record->cancel;
-
- $error = $record->suspend;
-
- $error = $record->unsuspend;
-
- $error = FS::cust_pkg::order( $custnum, \@pkgparts );
- $error = FS::cust_pkg::order( $custnum, \@pkgparts, \@remove_pkgnums ] );
-
-DESCRIPTION
- An FS::cust_pkg object represents a customer billing item.
- FS::cust_pkg inherits from FS::Record. The following fields are
- currently supported:
-
- pkgnum - primary key (assigned automatically for new billing items)
- custnum - Customer (see the FS::cust_main manpage)
- pkgpart - Billing item definition (see the FS::part_pkg manpage)
- setup - date
- bill - date
- susp - date
- expire - date
- cancel - date
- otaker - order taker (assigned automatically if null, see the FS::UID manpage)
- Note: setup, bill, susp, expire and cancel are specified as UNIX
- timestamps; see the section on "time" in the perlfunc manpage.
- Also see the Time::Local manpage and the Date::Parse manpage for
- conversion functions.
-
-METHODS
- create HASHREF
- Create a new billing item. To add the item to the database,
- see the section on "insert".
-
- insert
- Adds this billing item to the database ("Orders" the item).
- If there is an error, returns the error, otherwise returns
- false.
-
- delete
- Currently unimplemented. You don't want to delete billing
- items, because there would then be no record the customer
- ever purchased the item. Instead, see the cancel method.
-
- sub delete { return "Can't delete cust_pkg records!"; }
-
- replace OLD_RECORD
- Replaces the OLD_RECORD with this one in the database. If
- there is an error, returns the error, otherwise returns
- false.
-
- Currently, custnum, setup, bill, susp, expire, and cancel
- may be changed.
-
- pkgpart may not be changed, but see the order subroutine.
-
- setup and bill are normally updated by calling the bill
- method of a customer object (see the FS::cust_main manpage).
-
- suspend is normally updated by the suspend and unsuspend
- methods.
-
- cancel is normally updated by the cancel method (and also
- the order subroutine in some cases).
-
- check
- Checks all fields to make sure this is a valid billing item.
- If there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
- cancel
- Cancels and removes all services (see the FS::cust_svc
- manpage and the FS::part_svc manpage) in this package, then
- cancels the package itself (sets the cancel field to now).
-
- If there is an error, returns the error, otherwise returns
- false.
-
- suspend
- Suspends all services (see the FS::cust_svc manpage and the
- FS::part_svc manpage) in this package, then suspends the
- package itself (sets the susp field to now).
-
- If there is an error, returns the error, otherwise returns
- false.
-
- unsuspend
- Unsuspends all services (see the FS::cust_svc manpage and
- the FS::part_svc manpage) in this package, then unsuspends
- the package itself (clears the susp field).
-
- If there is an error, returns the error, otherwise returns
- false.
-
-SUBROUTINES
- order CUSTNUM, PKGPARTS_ARYREF, [ REMOVE_PKGNUMS_ARYREF ]
- CUSTNUM is a customer (see the FS::cust_main manpage)
-
- PKGPARTS is a list of pkgparts specifying the the billing
- item definitions (see the FS::part_pkg manpage) to order for
- this customer. Duplicates are of course permitted.
-
- REMOVE_PKGNUMS is an optional list of pkgnums specifying the
- billing items to remove for this customer. The services (see
- the FS::cust_svc manpage) are moved to the new billing
- items. An error is returned if this is not possible (see the
- FS::pkg_svc manpage).
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- sub order is not OO. Perhaps it should be moved to FS::cust_main
- and made so?
-
- In sub order, the @pkgparts array (passed by reference) is
- clobbered.
-
- Also in sub order, no money is adjusted. Once FS::part_pkg
- defines a standard method to pass dates to the recur_prog
- expression, it should do so.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_main manpage, the
- FS::part_pkg manpage, the FS::cust_svc manpage , the FS::pkg_svc
- manpage, schema.html from the base documentation
-
-HISTORY
- ivan@voicenet.com 97-jul-1 - 21
-
- fixed for new agent->agent_type->type_pkgs in &order
- ivan@sisd.com 98-mar-7
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/cust_refund.txt b/htdocs/docs/man/cust_refund.txt
deleted file mode 100644
index 392a0b57a..000000000
--- a/htdocs/docs/man/cust_refund.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-NAME
- FS::cust_refund - Object method for cust_refund objects
-
-SYNOPSIS
- use FS::cust_refund;
-
- $record = create FS::cust_refund \%hash;
- $record = create FS::cust_refund { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::cust_refund represents a refund. FS::cust_refund inherits
- from FS::Record. The following fields are currently supported:
-
- refundnum - primary key (assigned automatically for new refunds)
- crednum - Credit (see the FS::cust_credit manpage)
- refund - Amount of the refund
- _date - specified as a UNIX timestamp; see the section on "time" in the perlfunc manpage. Also see
- the Time::Local manpage and the Date::Parse manpage for conversion functions.
- payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)
- payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)
- otaker - order taker (assigned automatically, see the FS::UID manpage)
-METHODS
- create HASHREF
- Creates a new refund. To add the refund to the database, see
- the section on "insert".
-
- insert
- Adds this refund to the database, and updates the credit
- (see the FS::cust_credit manpage).
-
- delete
- Currently unimplemented (accounting reasons).
-
- replace OLD_RECORD
- Currently unimplemented (accounting reasons).
-
- check
- Checks all fields to make sure this is a valid refund. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert method.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- Delete and replace methods.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_credit manpage, schema.html
- from the base documentation.
-
-HISTORY
- ivan@sisd.com 98-mar-18
-
- ->create had wrong tablename ivan@sisd.com 98-jun-16 (finish
- me!)
-
- pod and finish up ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/cust_svc.txt b/htdocs/docs/man/cust_svc.txt
deleted file mode 100644
index d863ea852..000000000
--- a/htdocs/docs/man/cust_svc.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-NAME
- FS::cust_svc - Object method for cust_svc objects
-
-SYNOPSIS
- use FS::cust_svc;
-
- $record = create FS::cust_svc \%hash
- $record = create FS::cust_svc { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::cust_svc represents a service. FS::cust_svc inherits from
- FS::Record. The following fields are currently supported:
-
- svcnum - primary key (assigned automatically for new services)
- pkgnum - Package (see the FS::cust_pkg manpage)
- svcpart - Service definition (see the FS::part_svc manpage)
-METHODS
- create HASHREF
- Creates a new service. To add the refund to the database,
- see the section on "insert". Services are normally created
- by creating FS::svc_ objects (see the FS::svc_acct manpage,
- the FS::svc_domain manpage, and the FS::svc_acct_sm manpage,
- among others).
-
- insert
- Adds this service to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Deletes this service from the database. If there is an
- error, returns the error, otherwise returns false.
-
- Called by the cancel method of the package (see the
- FS::cust_pkg manpage).
-
- replace OLD_RECORD
- Replaces the OLD_RECORD with this one in the database. If
- there is an error, returns the error, otherwise returns
- false.
-
- check
- Checks all fields to make sure this is a valid service. If
- there is an error, returns the error, otehrwise returns
- false. Called by the insert and replace methods.
-
-BUGS
- Behaviour of changing the svcpart of cust_svc records is
- undefined and should possibly be prohibited, and pkg_svc records
- are not checked.
-
- pkg_svc records are not checket in general (here).
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_pkg manpage, the
- FS::part_svc manpage, the FS::pkg_svc manpage, schema.html from
- the base documentation
-
-HISTORY
- ivan@voicenet.com 97-jul-10,14
-
- no TableUtil, no FS::Lock ivan@sisd.com 98-mar-7
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/dbdef.txt b/htdocs/docs/man/dbdef.txt
deleted file mode 100644
index 6f1215a84..000000000
--- a/htdocs/docs/man/dbdef.txt
+++ /dev/null
@@ -1,80 +0,0 @@
-NAME
- FS::dbdef - Database objects
-
-SYNOPSIS
- use FS::dbdef;
-
- $dbdef = new FS::dbdef (@dbdef_table_objects);
- $dbdef = load FS::dbdef "filename";
-
- $dbdef->save("filename");
-
- $dbdef->addtable($dbdef_table_object);
-
- @table_names = $dbdef->tables;
-
- $FS_dbdef_table_object = $dbdef->table;
-
-DESCRIPTION
- FS::dbdef objects are collections of FS::dbdef_table objects and
- represnt a database (a collection of tables).
-
-METHODS
- new TABLE, TABLE, ...
- Creates a new FS::dbdef object
-
- load FILENAME
- Loads an FS::dbdef object from a file.
-
- save FILENAME
- Saves an FS::dbdef object to a file.
-
- addtable TABLE
- Adds this FS::dbdef_table object.
-
- tables
- Returns the names of all tables.
-
- table TABLENAME
- Returns the named FS::dbdef_table object.
-
-BUGS
- Each FS::dbdef object should have a name which corresponds
- to its name within the SQL database engine.
-
-SEE ALSO
- the FS::dbdef_table manpage, the FS::Record manpage,
-
-HISTORY
- beginning of abstraction into a class (not really)
-
- ivan@sisd.com 97-dec-4
-
- added primary_key ivan@sisd.com 98-jan-20
-
- added datatype (very kludgy and needs to be cleaned)
- ivan@sisd.com 98-feb-21
-
- perltrap (sigh) masked by mysql 3.20->3,21 ivan@sisd.com 98-
- mar-2
-
- Change 'type' to 'atype' in agent_type Changed attributes to
- special words which are changed in fs-setup ie. double(10,2)
- <=> MONEYTYPE Changed order of some of the field definitions
- because Pg6.3 is picky Changed 'day' to 'daytime' in
- cust_main Changed type of tax from tinyint to real Change
- 'password' to '_password' in svc_acct Pg6.3 does not allow
- 'field char(x) NULL' bmccane@maxbaud.net 98-apr-3
-
- rewrite: now properly OO. See also
- FS::dbdef_{table,column,unique,index}
-
- ivan@sisd.com 98-apr-17
-
- gained some extra functions ivan@sisd.com 98-may-11
-
- now knows how to Freeze and Thaw itself ivan@sisd.com 98-
- jun-2
-
- pod ivan@sisd.com 98-sep-23
-
diff --git a/htdocs/docs/man/dbdef_colgroup.txt b/htdocs/docs/man/dbdef_colgroup.txt
deleted file mode 100644
index a7eebc6c7..000000000
--- a/htdocs/docs/man/dbdef_colgroup.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-NAME
- FS::dbdef_colgroup - Column group objects
-
-SYNOPSIS
- use FS::dbdef_colgroup;
-
- $colgroup = new FS::dbdef_colgroup ( $lol );
- $colgroup = new FS::dbdef_colgroup (
- [
- [ 'single_column' ],
- [ 'multiple_columns', 'another_column', ],
- ]
- );
-
- @sql_lists = $colgroup->sql_list;
-
- @singles = $colgroup->singles;
-
-DESCRIPTION
- FS::dbdef_colgroup objects represent sets of sets of columns.
-
-METHODS
- new Creates a new FS::dbdef_colgroup object.
-
- sql_list
- Returns a flat list of comma-separated values, for SQL
- statements.
-
- singles
- Returns a flat list of all single item lists.
-
-BUGS
-SEE ALSO
- the FS::dbdef_table manpage, the FS::dbdef_unique manpage, the
- FS::dbdef_index manpage, the FS::dbdef_column manpage, the
- FS::dbdef manpage, the perldsc manpage
-
-HISTORY
- class for dealing with groups of groups of columns (used as a
- base class by FS::dbdef_{unique,index} )
-
- ivan@sisd.com 98-apr-19
-
- added singles, fixed sql_list to skip empty lists ivan@sisd.com
- 98-jun-2
-
- untaint things we're returning in sub singels ivan@sisd.com 98-
- jun-4
-
- pod ivan@sisd.com 98-sep-24
-
diff --git a/htdocs/docs/man/dbdef_column.txt b/htdocs/docs/man/dbdef_column.txt
deleted file mode 100644
index 93e239517..000000000
--- a/htdocs/docs/man/dbdef_column.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-NAME
- FS::dbdef_column - Column object
-
-SYNOPSIS
- use FS::dbdef_column;
-
- $column_object = new FS::dbdef_column ( $name, $sql_type, '' );
- $column_object = new FS::dbdef_column ( $name, $sql_type, 'NULL' );
- $column_object = new FS::dbdef_column ( $name, $sql_type, '', $length );
- $column_object = new FS::dbdef_column ( $name, $sql_type, 'NULL', $length );
-
- $name = $column_object->name;
- $column_object->name ( 'name' );
-
- $name = $column_object->type;
- $column_object->name ( 'sql_type' );
-
- $name = $column_object->null;
- $column_object->name ( 'NOT NULL' );
-
- $name = $column_object->length;
- $column_object->name ( $length );
-
- $sql_line = $column->line;
- $sql_line = $column->line $datasrc;
-
-DESCRIPTION
- FS::dbdef::column objects represend columns in tables (see the
- FS::dbdef_table manpage).
-
-METHODS
- new Creates a new FS::dbdef_column object.
-
- name
- Returns or sets the column name.
-
- type
- Returns or sets the column type.
-
- null
- Returns or sets the column null flag.
-
- type
- Returns or sets the column length.
-
- line [ $datasrc ]
- Returns an SQL column definition.
-
- If passed a DBI $datasrc specifying the DBD::mysql manpage,
- will use MySQL-specific syntax. Non-standard syntax for
- other engines (if applicable) may also be supported in the
- future.
-
-BUGS
-SEE ALSO
- the FS::dbdef_table manpage, the FS::dbdef manpage, the DBI
- manpage
-
-HISTORY
- class for dealing with column definitions
-
- ivan@sisd.com 98-apr-17
-
- now methods can be used to get or set data ivan@sisd.com 98-may-
- 11
-
- mySQL-specific hack for null (what should be default?)
- ivan@sisd.com 98-jun-2
-
diff --git a/htdocs/docs/man/dbdef_index.txt b/htdocs/docs/man/dbdef_index.txt
deleted file mode 100644
index 8cf339b84..000000000
--- a/htdocs/docs/man/dbdef_index.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-NAME
- FS::dbdef_unique.pm - Index object
-
-SYNOPSIS
- use FS::dbdef_index;
-
- # see FS::dbdef_colgroup methods
-
-DESCRIPTION
- FS::dbdef_unique objects represent the (non-unique) indices of a
- table (the FS::dbdef_table manpage). FS::dbdef_unique inherits
- from FS::dbdef_colgroup.
-
-BUGS
- Is this empty subclass needed?
-
-SEE ALSO
- the FS::dbdef_colgroup manpage, the FS::dbdef_record manpage,
- the FS::Record manpage
-
-HISTORY
- class for dealing with index definitions
-
- ivan@sisd.com 98-apr-19
-
- pod ivan@sisd.com 98-sep-24
-
diff --git a/htdocs/docs/man/dbdef_table.txt b/htdocs/docs/man/dbdef_table.txt
deleted file mode 100644
index 25e010d8b..000000000
--- a/htdocs/docs/man/dbdef_table.txt
+++ /dev/null
@@ -1,94 +0,0 @@
-NAME
- FS::dbdef_table - Table objects
-
-SYNOPSIS
- use FS::dbdef_table;
-
- $dbdef_table = new FS::dbdef_table (
- "table_name",
- "primary_key",
- $FS_dbdef_unique_object,
- $FS_dbdef_index_object,
- @FS_dbdef_column_objects,
- );
-
- $dbdef_table->addcolumn ( $FS_dbdef_column_object );
-
- $table_name = $dbdef_table->name;
- $dbdef_table->name ("table_name");
-
- $table_name = $dbdef_table->primary_keye;
- $dbdef_table->primary_key ("primary_key");
-
- $FS_dbdef_unique_object = $dbdef_table->unique;
- $dbdef_table->unique ( $FS_dbdef_unique_object );
-
- $FS_dbdef_index_object = $dbdef_table->index;
- $dbdef_table->index ( $FS_dbdef_index_object );
-
- @column_names = $dbdef->columns;
-
- $FS_dbdef_column_object = $dbdef->column;
-
- @sql_statements = $dbdef->sql_create_table;
- @sql_statements = $dbdef->sql_create_table $datasrc;
-
-DESCRIPTION
- FS::dbdef_table objects represent a single database table.
-
-METHODS
- new Creates a new FS::dbdef_table object.
-
- addcolumn
- Adds this FS::dbdef_column object.
-
- name
- Returns or sets the table name.
-
- primary_key
- Returns or sets the primary key.
-
- unique
- Returns or sets the FS::dbdef_unique object.
-
- index
- Returns or sets the FS::dbdef_index object.
-
- columns
- Returns a list consisting of the names of all columns.
-
- column "column"
- Returns the column object (see the FS::dbdef_column manpage)
- for "column".
-
- sql_create_table [ $datasrc ]
- Returns an array of SQL statments to create this table.
-
- If passed a DBI $datasrc specifying the DBD::mysql manpage,
- will use MySQL-specific syntax. Non-standard syntax for
- other engines (if applicable) may also be supported in the
- future.
-
-BUGS
-SEE ALSO
- the FS::dbdef manpage, the FS::dbdef_unique manpage, the
- FS::dbdef_index manpage, the FS::dbdef_unique manpage, the DBI
- manpage
-
-HISTORY
- class for dealing with table definitions
-
- ivan@sisd.com 98-apr-18
-
- gained extra functions (should %columns be an IxHash?)
- ivan@sisd.com 98-may-11
-
- sql_create_table returns a list of statments, not just one, and
- now it does indices (plus mysql hack) ivan@sisd.com 98-jun-2
-
- untaint primary_key... hmm. is this a hack around a bigger
- problem? looks like, did the same thing singles in colgroup!
- ivan@sisd.com 98-jun-4
-
- pod ivan@sisd.com 98-sep-24
-
diff --git a/htdocs/docs/man/dbdef_unique.txt b/htdocs/docs/man/dbdef_unique.txt
deleted file mode 100644
index 0e4f0150b..000000000
--- a/htdocs/docs/man/dbdef_unique.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-NAME
- FS::dbdef_unique.pm - Unique object
-
-SYNOPSIS
- use FS::dbdef_unique;
-
- # see FS::dbdef_colgroup methods
-
-DESCRIPTION
- FS::dbdef_unique objects represent the unique indices of a
- database table (the FS::dbdef_table manpage). FS::dbdef_unique
- inherits from FS::dbdef_colgroup.
-
-BUGS
- Is this empty subclass needed?
-
-SEE ALSO
- the FS::dbdef_colgroup manpage, the FS::dbdef_record manpage,
- the FS::Record manpage
-
-HISTORY
- class for dealing with unique definitions
-
- ivan@sisd.com 98-apr-19
-
- pod ivan@sisd.com 98-sep-24
-
diff --git a/htdocs/docs/man/index.html b/htdocs/docs/man/index.html
deleted file mode 100644
index 4f33dd485..000000000
--- a/htdocs/docs/man/index.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<head>
- <title>Perl API</title>
-</head>
-<body>
- <h1>Perl API</h1>
- <ul>
-<li><a href="agent.txt">FS::agent</a>
-<li><a href="agent_type.txt">FS::agent_type</a>
-<li><a href="cust_bill.txt">FS::cust_bill</a>
-<li><a href="cust_bill_pkg.txt">FS::cust_bill_pkg</a>
-<li><a href="cust_credit.txt">FS::cust_credit</a>
-<li><a href="cust_main.txt">FS::cust_main</a>
-<li><a href="cust_main_county.txt">FS::cust_main_county</a>
-<li><a href="cust_pay.txt">FS::cust_pay</a>
-<li><a href="cust_pkg.txt">FS::cust_pkg</a>
-<li><a href="cust_refund.txt">FS::cust_refund</a>
-<li><a href="cust_svc.txt">FS::cust_svc</a>
-<li><a href="part_pkg.txt">FS::part_pkg</a>
-<li><a href="part_referral.txt">FS::part_referral</a>
-<li><a href="part_svc.txt">FS::part_svc</a>
-<li><a href="pkg_svc.txt">FS::pkg_svc</a>
-<li><a href="svc_acct.txt">FS::svc_acct</a>
-<li><a href="svc_acct_pop.txt">FS::svc_acct_pop</a>
-<li><a href="svc_acct_sm.txt">FS::svc_acct_sm</a>
-<li><a href="svc_domain.txt">FS::svc_domain</a>
-<li><a href="type_pkgs.txt">FS::type_pkgs</a>
-</ul>
-<br>
-<ul>
-<li><a href="Bill.txt">FS::Bill</a>
-<li><a href="CGI.txt">FS::CGI</a>
-<li><a href="Conf.txt">FS::Conf</a>
-<li><a href="Invoice.txt">FS::Invoice</a>
-<li><a href="Record.txt">FS::Record</a>
-<li><a href="SSH.txt">FS::SSH</a>
-<li><a href="UID.txt">FS::UID</a>
-</ul>
-<br>
-<ul>
-<li><a href="dbdef.txt">FS::dbdef</a>
-<li><a href="dbdef_colgroup.txt">FS::dbdef_colgroup</a>
-<li><a href="dbdef_column.txt">FS::dbdef_column</a>
-<li><a href="dbdef_index.txt">FS::dbdef_index</a>
-<li><a href="dbdef_table.txt">FS::dbdef_table</a>
-<li><a href="dbdef_unique.txt">FS::dbdef_unique</a>
-
-<ul>
-</body>
diff --git a/htdocs/docs/man/part_pkg.txt b/htdocs/docs/man/part_pkg.txt
deleted file mode 100644
index dc1bce423..000000000
--- a/htdocs/docs/man/part_pkg.txt
+++ /dev/null
@@ -1,73 +0,0 @@
-NAME
- FS::part_pkg - Object methods for part_pkg objects
-
-SYNOPSIS
- use FS::part_pkg;
-
- $record = create FS::part_pkg \%hash
- $record = create FS::part_pkg { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::part_pkg represents a billing item definition.
- FS::part_pkg inherits from FS::Record. The following fields are
- currently supported:
-
- pkgpart - primary key (assigned automatically for new billing item definitions)
- pkg - Text name of this billing item definition (customer-viewable)
- comment - Text name of this billing item definition (non-customer-viewable)
- setup - Setup fee
- freq - Frequency of recurring fee
- recur - Recurring fee
- setup and recur are evaluated as Safe perl expressions. You can
- use numbers just as you would normally. More advanced semantics
- are not yet defined.
-
-METHODS
- create HASHREF
- Creates a new billing item definition. To add the billing
- item definition to the database, see the section on
- "insert".
-
- insert
- Adds this billing item definition to the database. If there
- is an error, returns the error, otherwise returns false.
-
- delete
- Currently unimplemented.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid billing item
- definition. If there is an error, returns the error,
- otherwise returns false. Called by the insert and replace
- methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- The delete method is unimplemented.
-
- setup and recur semantics are not yet defined (and are
- implemented in FS::cust_bill. hmm.).
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_pkg manpage, the
- FS::type_pkgs manpage, the FS::pkg_svc manpage, the Safe
- manpage. schema.html from the base documentation.
-
-HISTORY
- ivan@sisd.com 97-dec-5
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/part_referral.txt b/htdocs/docs/man/part_referral.txt
deleted file mode 100644
index 534996323..000000000
--- a/htdocs/docs/man/part_referral.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-NAME
- FS::part_referral - Object methods for part_referral objects
-
-SYNOPSIS
- use FS::part_referral;
-
- $record = create FS::part_referral \%hash
- $record = create FS::part_referral { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::part_referral represents a referral - where a customer
- heard of your services. This can be used to track the
- effectiveness of a particular piece of advertising, for example.
- FS::part_referral inherits from FS::Record. The following fields
- are currently supported:
-
- refnum - primary key (assigned automatically for new referrals)
- referral - Text name of this referral
-METHODS
- create HASHREF
- Creates a new referral. To add the referral to the database,
- see the section on "insert".
-
- insert
- Adds this referral to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Currently unimplemented.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid referral. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- The delete method is unimplemented.
-
-SEE ALSO
- the FS::Record manpage, the FS::cust_main manpage, schema.html
- from the base documentation.
-
-HISTORY
- Class dealing with referrals
-
- ivan@sisd.com 98-feb-23
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/part_svc.txt b/htdocs/docs/man/part_svc.txt
deleted file mode 100644
index 680944e2f..000000000
--- a/htdocs/docs/man/part_svc.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-NAME
- FS::part_svc - Object methods for part_svc objects
-
-SYNOPSIS
- use FS::part_svc;
-
- $record = create FS::part_referral \%hash
- $record = create FS::part_referral { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::part_svc represents a service definition. FS::part_svc
- inherits from FS::Record. The following fields are currently
- supported:
-
- svcpart - primary key (assigned automatically for new service definitions)
- svc - text name of this service definition
- svcdb - table used for this service. See the FS::svc_acct manpage,
- the FS::svc_domain manpage, and the FS::svc_acct_sm manpage, among others.
- *svcdb*__*field* - Default or fixed value for *field* in *svcdb*.
- *svcdb*__*field*_flag - defines *svcdb*__*field* action: null, `D' for default, or `F' for fixed
-METHODS
- create HASHREF
- Creates a new service definition. To add the service
- definition to the database, see the section on "insert".
-
- insert
- Adds this service definition to the database. If there is an
- error, returns the error, otherwise returns false.
-
- delete
- Currently unimplemented.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid service
- definition. If there is an error, returns the error,
- otherwise returns false. Called by the insert and replace
- methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- Delete is unimplemented.
-
-SEE ALSO
- the FS::Record manpage, the FS::part_pkg manpage, the
- FS::pkg_svc manpage, the FS::cust_svc manpage, the FS::svc_acct
- manpage, the FS::svc_acct_sm manpage, the FS::svc_domain
- manpage, schema.html from the base documentation.
-
-HISTORY
- ivan@sisd.com 97-nov-14
-
- data checking/untainting calls into FS::Record added
- ivan@sisd.com 97-dec-6
-
- pod ivan@sisd.com 98-sep-21
-
diff --git a/htdocs/docs/man/pkg_svc.txt b/htdocs/docs/man/pkg_svc.txt
deleted file mode 100644
index bde0043f1..000000000
--- a/htdocs/docs/man/pkg_svc.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-NAME
- FS::pkg_svc - Object methods for pkg_svc records
-
-SYNOPSIS
- use FS::pkg_svc;
-
- $record = create FS::pkg_svc \%hash;
- $record = create FS::pkg_svc { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::pkg_svc record links a billing item definition (see the
- FS::part_pkg manpage) to a service definition (see the
- FS::part_svc manpage). FS::pkg_svc inherits from FS::Record. The
- following fields are currently supported:
-
- pkgpart - Billing item definition (see the FS::part_pkg manpage)
- svcpart - Service definition (see the FS::part_svc manpage)
- quantity - Quantity of this service definition that this billing item
- definition includes
-METHODS
- create HASHREF
- Create a new record. To add the record to the database, see
- the section on "insert".
-
- insert
- Adds this record to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Deletes this record from the database. If there is an error,
- returns the error, otherwise returns false.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid record. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
-SEE ALSO
- the FS::Record manpage, the FS::part_pkg manpage, the
- FS::part_svc manpage, schema.html from the base documentation.
-
-HISTORY
- ivan@voicenet.com 97-jul-1 added hfields ivan@sisd.com 97-nov-13
-
- pod ivan@sisd.com 98-sep-22
-
diff --git a/htdocs/docs/man/svc_acct.txt b/htdocs/docs/man/svc_acct.txt
deleted file mode 100644
index 1c9caf5fb..000000000
--- a/htdocs/docs/man/svc_acct.txt
+++ /dev/null
@@ -1,168 +0,0 @@
-NAME
- FS::svc_acct - Object methods for svc_acct records
-
-SYNOPSIS
- use FS::svc_acct;
-
- $record = create FS::svc_acct \%hash;
- $record = create FS::svc_acct { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
- $error = $record->suspend;
-
- $error = $record->unsuspend;
-
- $error = $record->cancel;
-
-DESCRIPTION
- An FS::svc_acct object represents an account. FS::svc_acct
- inherits from FS::Record. The following fields are currently
- supported:
-
- svcnum - primary key (assigned automatcially for new accounts)
- username
- _password - generated if blank
- popnum - Point of presence (see the FS::svc_acct_pop manpage)
- uid
- gid
- finger - GECOS
- dir - set automatically if blank (and uid is not)
- shell
- quota - (unimplementd)
- slipip - IP address
- radius_*Radius_Attribute* - *Radius-Attribute*
-METHODS
- create HASHREF
- Creates a new account. To add the account to the database,
- see the section on "insert".
-
- insert
- Adds this account to the database. If there is an error,
- returns the error, otherwise returns false.
-
- The additional fields pkgnum and svcpart (see the
- FS::cust_svc manpage) should be defined. An FS::cust_svc
- record will be created and inserted.
-
- If the configuration value (see the FS::Conf manpage)
- shellmachine exists, and the username, uid, and dir fields
- are defined, the command
-
- useradd -d $dir -m -s $shell -u $uid $username
-
- is executed on shellmachine via ssh. This behaviour can be
- surpressed by setting $FS::svc_acct::nossh_hack true.
-
- delete
- Deletes this account from the database. If there is an
- error, returns the error, otherwise returns false.
-
- The corresponding FS::cust_svc record will be deleted as
- well.
-
- If the configuration value (see the FS::Conf manpage)
- shellmachine exists, the command:
-
- userdel $username
-
- is executed on shellmachine via ssh. This behaviour can be
- surpressed by setting $FS::svc_acct::nossh_hack true.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- If the configuration value (see the FS::Conf manpage)
- shellmachine exists, and the dir field has changed, the
- command:
-
- [ -d $old_dir ] && (
- chmod u+t $old_dir;
- umask 022;
- mkdir $new_dir;
- cd $old_dir;
- find . -depth -print | cpio -pdm $new_dir;
- chmod u-t $new_dir;
- chown -R $uid.$gid $new_dir;
- rm -rf $old_dir
- )
-
- is executed on shellmachine via ssh. This behaviour can be
- surpressed by setting $FS::svc_acct::nossh_hack true.
-
- suspend
- Suspends this account by prefixing *SUSPENDED* to the
- password. If there is an error, returns the error, otherwise
- returns false.
-
- Called by the suspend method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- unsuspend
- Unsuspends this account by removing *SUSPENDED* from the
- password. If there is an error, returns the error, otherwise
- returns false.
-
- Called by the unsuspend method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- cancel
- Just returns false (no error) for now.
-
- Called by the cancel method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- check
- Checks all fields to make sure this is a valid service. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
- Sets any fixed values; see the FS::part_svc manpage.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- The remote commands should be configurable.
-
- The create method should set defaults from part_svc (like the
- check method sets fixed values).
-
-SEE ALSO
- the FS::Record manpage, the FS::Conf manpage, the FS::cust_svc
- manpage, the FS::part_svc manpage, the FS::cust_pkg manpage, the
- FS::SSH manpage, the ssh manpage, the FS::svc_acct_pop manpage,
- schema.html from the base documentation.
-
-HISTORY
- ivan@voicenet.com 97-jul-16 - 21
-
- rewrite (among other things, now know about part_svc)
- ivan@sisd.com 98-mar-8
-
- Changed 'password' to '_password' because Pg6.3 reserves the
- password word bmccane@maxbaud.net 98-apr-3
-
- username length and shell no longer hardcoded ivan@sisd.com 98-
- jun-28
-
- eww but needed: ignore uid duplicates for 'fax' and 'hylafax'
- ivan@sisd.com 98-jun-29
-
- $nossh_hack ivan@sisd.com 98-jul-13
-
- protections against UID/GID of 0 for incorrectly-setup RDBMSs
- (also in bin/svc_acct.export) ivan@sisd.com 98-jul-13
-
- arbitrary radius attributes ivan@sisd.com 98-aug-13
-
- /var/spool/freeside/conf/shellmachine ivan@sisd.com 98-aug-13
-
- pod and FS::conf ivan@sisd.com 98-sep-22
-
diff --git a/htdocs/docs/man/svc_acct_pop.txt b/htdocs/docs/man/svc_acct_pop.txt
deleted file mode 100644
index ac0965413..000000000
--- a/htdocs/docs/man/svc_acct_pop.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-NAME
- FS::svc_acct_pop - Object methods for svc_acct_pop records
-
-SYNOPSIS
- use FS::svc_acct_pop;
-
- $record = create FS::svc_acct_pop \%hash;
- $record = create FS::svc_acct_pop { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::svc_acct object represents an point of presence.
- FS::svc_acct_pop inherits from FS::Record. The following fields
- are currently supported:
-
- popnum - primary key (assigned automatically for new accounts)
- city
- state
- ac - area code
- exch - exchange
-METHODS
- create HASHREF
- Creates a new point of presence (if only it were that
- easy!). To add the point of presence to the database, see
- the section on "insert".
-
- insert
- Adds this point of presence to the databaes. If there is an
- error, returns the error, otherwise returns false.
-
- delete
- Currently unimplemented.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid point of
- presence. If there is an error, returns the error, otherwise
- returns false. Called by the insert and replace methods.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- It should be renamed to part_pop.
-
-SEE ALSO
- the FS::Record manpage, the svc_acct manpage, schema.html from
- the base documentation.
-
-HISTORY
- Class dealing with pops
-
- ivan@sisd.com 98-mar-8
-
- pod ivan@sisd.com 98-sep-23
-
diff --git a/htdocs/docs/man/svc_acct_sm.txt b/htdocs/docs/man/svc_acct_sm.txt
deleted file mode 100644
index e9940af9a..000000000
--- a/htdocs/docs/man/svc_acct_sm.txt
+++ /dev/null
@@ -1,121 +0,0 @@
-NAME
- FS::svc_acct_sm - Object methods for svc_acct_sm records
-
-SYNOPSIS
- use FS::svc_acct_sm;
-
- $record = create FS::svc_acct_sm \%hash;
- $record = create FS::svc_acct_sm { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
- $error = $record->suspend;
-
- $error = $record->unsuspend;
-
- $error = $record->cancel;
-
-DESCRIPTION
- An FS::svc_acct object represents a virtual mail alias.
- FS::svc_acct inherits from FS::Record. The following fields are
- currently supported:
-
- svcnum - primary key (assigned automatcially for new accounts)
- domsvc - svcnum of the virtual domain (see the FS::svc_domain manpage)
- domuid - uid of the target account (see the FS::svc_acct manpage)
- domuser - virtual username
-METHODS
- create HASHREF
- Creates a new virtual mail alias. To add the virtual mail
- alias to the database, see the section on "insert".
-
- insert
- Adds this virtual mail alias to the database. If there is an
- error, returns the error, otherwise returns false.
-
- The additional fields pkgnum and svcpart (see the
- FS::cust_svc manpage) should be defined. An FS::cust_svc
- record will be created and inserted.
-
- If the configuration values (see the FS::Conf manpage)
- shellmachine and qmailmachines exist, and domuser is `*'
- (meaning a catch-all mailbox), the command:
-
- [ -e $dir/.qmail-$qdomain-default ] || {
- touch $dir/.qmail-$qdomain-default;
- chown $uid:$gid $dir/.qmail-$qdomain-default;
- }
-
- is executed on shellmachine via ssh (see the section on
- "EXTENSION ADDRESSES" in the dot-qmail manpage). This
- behaviour can be surpressed by setting
- $FS::svc_acct_sm::nossh_hack true.
-
- delete
- Deletes this virtual mail alias from the database. If there
- is an error, returns the error, otherwise returns false.
-
- The corresponding FS::cust_svc record will be deleted as
- well.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- suspend
- Just returns false (no error) for now.
-
- Called by the suspend method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- unsuspend
- Just returns false (no error) for now.
-
- Called by the unsuspend method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- cancel
- Just returns false (no error) for now.
-
- Called by the cancel method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- check
- Checks all fields to make sure this is a valid virtual mail
- alias. If there is an error, returns the error, otherwise
- returns false. Called by the insert and replace methods.
-
- Sets any fixed values; see the FS::part_svc manpage.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- The remote commands should be configurable.
-
-SEE ALSO
- the FS::Record manpage, the FS::Conf manpage, the FS::cust_svc
- manpage, the FS::part_svc manpage, the FS::cust_pkg manpage, the
- FS::svc_acct manpage, the FS::svc_domain manpage, the FS::SSH
- manpage, the ssh manpage, the dot-qmail manpage, schema.html
- from the base documentation.
-
-HISTORY
- ivan@voicenet.com 97-jul-16 - 21
-
- rewrite ivan@sisd.com 98-mar-10
-
- s/qsearchs/qsearch/ to eliminate warning ivan@sisd.com 98-apr-19
-
- uses conf/shellmachine and has an nossh_hack ivan@sisd.com 98-
- jul-14
-
- s/\./:/g in .qmail-domain:com ivan@sisd.com 98-aug-13
-
- pod, FS::Conf, moved .qmail file from check to insert 98-sep-23
-
diff --git a/htdocs/docs/man/svc_domain.txt b/htdocs/docs/man/svc_domain.txt
deleted file mode 100644
index 03d3dbc27..000000000
--- a/htdocs/docs/man/svc_domain.txt
+++ /dev/null
@@ -1,131 +0,0 @@
-NAME
- FS::svc_domain - Object methods for svc_domain records
-
-SYNOPSIS
- use FS::svc_domain;
-
- $record = create FS::svc_domain \%hash;
- $record = create FS::svc_domain { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
- $error = $record->suspend;
-
- $error = $record->unsuspend;
-
- $error = $record->cancel;
-
-DESCRIPTION
- An FS::svc_domain object represents a domain. FS::svc_domain
- inherits from FS::Record. The following fields are currently
- supported:
-
- svcnum - primary key (assigned automatically for new accounts)
- domain
-METHODS
- create HASHREF
- Creates a new domain. To add the domain to the database, see
- the section on "insert".
-
- insert
- Adds this domain to the database. If there is an error,
- returns the error, otherwise returns false.
-
- The additional fields *pkgnum* and *svcpart* (see the
- FS::cust_svc manpage) should be defined. An FS::cust_svc
- record will be created and inserted.
-
- The additional field *action* should be set to *N* for new
- domains or *M* for transfers.
-
- A registration or transfer email will be submitted unless
- $FS::svc_domain::whois_hack is true.
-
- delete
- Deletes this domain from the database. If there is an error,
- returns the error, otherwise returns false.
-
- The corresponding FS::cust_svc record will be deleted as
- well.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- suspend
- Just returns false (no error) for now.
-
- Called by the suspend method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- unsuspend
- Just returns false (no error) for now.
-
- Called by the unsuspend method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- cancel
- Just returns false (no error) for now.
-
- Called by the cancel method of FS::cust_pkg (see the
- FS::cust_pkg manpage).
-
- check
- Checks all fields to make sure this is a valid domain. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
- Sets any fixed values; see the FS::part_svc manpage.
-
- _whois
- Executes the command:
-
- whois do $domain
-
- and returns the output.
-
- (Always returns *No match for domian "$domain".* if
- $FS::svc_domain::whois_hack is set true.)
-
- submit_internic
- Submits a registration email for this domain.
-
-BUGS
- It doesn't properly override FS::Record yet.
-
- All BIND/DNS fields should be included (and exported).
-
- All registries should be supported.
-
- Not all configuration access is through FS::Conf!
-
- Should change action to a real field.
-
-SEE ALSO
- the FS::Record manpage, the FS::Conf manpage, the FS::cust_svc
- manpage, the FS::part_svc manpage, the FS::cust_pkg manpage, the
- FS::SSH manpage, the ssh manpage, the dot-qmail manpage,
- schema.html from the base documentation, config.html from the
- base documentation.
-
-HISTORY
- ivan@voicenet.com 97-jul-21
-
- rewrite ivan@sisd.com 98-mar-10
-
- add internic bits ivan@sisd.com 98-mar-14
-
- Changed 'day' to 'daytime' because Pg6.3 reserves the day word
- bmccane@maxbaud.net 98-apr-3
-
- /var/spool/freeside/conf/registries/internic/, Mail::Internet,
- etc. ivan@sisd.com 98-jul-17-19
-
- pod, some FS::Conf (not complete) ivan@sisd.com 98-sep-23
-
diff --git a/htdocs/docs/man/type_pkgs.txt b/htdocs/docs/man/type_pkgs.txt
deleted file mode 100644
index 9822b4802..000000000
--- a/htdocs/docs/man/type_pkgs.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-NAME
- FS::type_pkgs - Object methods for type_pkgs records
-
-SYNOPSIS
- use FS::type_pkgs;
-
- $record = create FS::type_pkgs \%hash;
- $record = create FS::type_pkgs { 'column' => 'value' };
-
- $error = $record->insert;
-
- $error = $new_record->replace($old_record);
-
- $error = $record->delete;
-
- $error = $record->check;
-
-DESCRIPTION
- An FS::type_pkgs record links an agent type (see the
- FS::agent_type manpage) to a billing item definition (see the
- FS::part_pkg manpage). FS::type_pkgs inherits from FS::Record.
- The following fields are currently supported:
-
- typenum - Agent type, see the FS::agent_type manpage
- pkgpart - Billing item definition, see the FS::part_pkg manpage
-METHODS
- create HASHREF
- Create a new record. To add the record to the database, see
- the section on "insert".
-
- insert
- Adds this record to the database. If there is an error,
- returns the error, otherwise returns false.
-
- delete
- Deletes this record from the database. If there is an error,
- returns the error, otherwise returns false.
-
- replace OLD_RECORD
- Replaces OLD_RECORD with this one in the database. If there
- is an error, returns the error, otherwise returns false.
-
- check
- Checks all fields to make sure this is a valid record. If
- there is an error, returns the error, otherwise returns
- false. Called by the insert and replace methods.
-
-HISTORY
- Defines the relation between agent types and pkgparts (Which
- pkgparts can the different [types of] agents sell?)
-
- ivan@sisd.com 97-nov-13
-
- change to ut_ FS::Record, fixed bugs ivan@sisd.com 97-dec-10
-
diff --git a/htdocs/docs/postgresql.html b/htdocs/docs/postgresql.html
new file mode 100755
index 000000000..151081176
--- /dev/null
+++ b/htdocs/docs/postgresql.html
@@ -0,0 +1,23 @@
+<head>
+ <title>PostgreSQL notes</title>
+</head>
+<body>
+ <h1>PostgreSQL notes</h1>
+<p>
+PostgreSQL ships by default with a maximum of 31 character column names. If
+you use arbitrary RADIUS attributes longer than 9 characters, fs-setup will
+fail with `duplicate column' errors (in the part_svc table).
+Solution: use a different database
+engine, or recompile PostgreSQL with 64 character column names.
+</p>
+Future versions of Freeside will keep all column names under 31 characters to
+avoid this problem.
+</p>
+<p>
+( I've personally been unable to get PostgreSQL working with larger column names,
+though the process does look like it should be straightforward. If anyone is
+interested in assisting me with this, please get in touch.
+ -Ivan <a href="mailto:ivan@sisd.com">&lt;ivan@sisd.com</a>&gt; )
+</p>
+</body>
+
diff --git a/htdocs/docs/schema.html b/htdocs/docs/schema.html
index 5a296ec83..3eea6f69d 100644
--- a/htdocs/docs/schema.html
+++ b/htdocs/docs/schema.html
@@ -50,7 +50,9 @@
<li>custnum - primary key
<li>agentnum - <a href="#agent">agent</a>
<li>refnum - <a href="#part_referral">referral</a>
+ <li>titlenum - <a href="#part_title">title</a>
<li>first - name
+ <li>middle - name
<li>last - name
<li>ss - social security number
<li>company
@@ -63,6 +65,7 @@
<li>country
<li>daytime - phone
<li>night - phone
+ <li>fax - phone
<li>payby - CARD, BILL, or COMP
<li>payinfo - card number, P.O.#, or comp issuer
<li>paydate - expiration date
@@ -70,11 +73,18 @@
<li>tax - tax exempt, Y or null
<li>otaker - order taker
</ul>
+ <li><a name="cust_main_invoice">cust_main_invoice</a> - Invoice destinations for email invoices
+ <ul>
+ <li>destnum - primary key
+ <li>custnum - <a href="#cust_main">customer</a>
+ <li>dest - Invoice destination: If numeric, a <a href="#svc_acct">svcnum</a>, if string, a literal email address, or `POST' to enable mailing (the default if no cust_main_invoice records exist)
+ </ul>
<li><a name="cust_main_county">cust_main_county</a> - Tax rates
<ul>
<li>taxnum - primary key
<li>state
<li>county
+ <li>country
<li>tax - % rate
</ul>
<li><a name="cust_pay">cust_pay</a> - Payments
@@ -144,8 +154,8 @@
</ul>
<li><a name="part_referral">part_referral</a> - Referral listing
<ul>
- <li>refnum</li> - primary key
- <li>referral</li> - referral
+ <li>refnum - primary key
+ <li>referral - referral
</ul>
<li><a name="part_svc">part_svc</a> - Service definitions
<ul>
@@ -155,12 +165,23 @@
<li><i>table</i>__<i>field</i> - Default or fixed value for <i>field</i> in <i>table</i>
<li><i>table</i>__<i>field</i>_flag - null, D or F
</ul>
+ <li><a name="part_title">part_title</a> - Personal titles
+ <ul>
+ <li>titlenum - primary key
+ <li>title - personal title (`Dr.' or `Mr.')
+ </ul>
<li><a name="pkg_svc">pkg_svc</a>
<ul>
<li>pkgpart - <a href="#part_pkg">Package definition</a>
<li>svcpart - <a href="#part_svc">Service definition</a>
<li>quantity - quantity of this service that this package includes
</ul>
+ <li><a name="prepay_credit">prepay_credit</a>
+ <ul>
+ <li>prepaynum - primary key
+ <li>identifier - text or numeric string used to receive this credit
+ <li>amount - amount of credit
+ </ul>
<li><a name="svc_acct">svc_acct</a> - Accounts
<ul>
<li>svcnum - <a href="#cust_svc">primary key</a>
@@ -183,6 +204,7 @@
<li>state
<li>ac - area code
<li>exch - exchange
+ <li>loc - rest of number
</ul>
<li><a name="svc_acct_sm">svc_acct_sm</a> - Domain mail aliases
<ul>
diff --git a/htdocs/docs/signup.html b/htdocs/docs/signup.html
new file mode 100644
index 000000000..fbd19df62
--- /dev/null
+++ b/htdocs/docs/signup.html
@@ -0,0 +1,47 @@
+<head>
+ <title>Signup server</title>
+</head>
+<body>
+ <h1>Signup server</h1>
+For security reasons, the signup server should run on an external public
+webserver. On this machine, install:
+<ul>
+ <li>A web server, such as <a href="http://www.apache-ssl.org">Apache-SSL</a> or <a href="http://www.apache.org">Apache</a>
+ <li><a href="ftp://ftp.cs.hut.fi/pub/ssh/">SSH</a>
+ <li><a href="http://www.perl.com/CPAN/doc/relinfo/INSTALL.html">Perl</a> (at least 5.004_05 for the 5.004 series or 5.005_03 for the 5.005 series. Don't enable experimental features like threads or the PerlIO abstraction layer.)
+ <li><a href="http://www.perl.com/CPAN/modules/by-module/Text/">Text::Template</a>
+ <li><a href="http://www.perl.com/CPAN/modules/by-author/IVAN/">HTTP::Headers::UserAgent</a> (version 2.0 or higher; not yet indexed correctly on CPAN)
+
+ <li><a href="man/FS/SignupClient.html">FS::SignupClient</a> (copy the fs_signup/FS-SignupClient directory to the external machine, then: perl Makefile.PL; make; make install)
+</ul>
+Then:
+<ul>
+ <li>Add the user `freeside' to the the external machine.
+ <li>Copy or symlink fs_signup/FS-SignupClient/cgi/signup.cgi into the web server's document space.
+ <li>Enable CGI execution for files with the `.cgi' extension. (with <a href="http://www.apache.org/docs/mod/mod_mime.html#addhandler">Apache</a>)
+ <li>Create the /usr/local/freeside directory on the external machine (owned by the freeside user).
+ <li>touch /usr/local/freeside/fs_signupd_socket; chown freeside /usr/local/freeside/fs_signupd_socket; chmod 600 /usr/local/freeside/fs_signupd_socket
+ <li>Use <a href="http://www.apache.org/docs/suexec.html">suEXEC</a> or <a href="http://www.perl.com/CPAN-local/doc/manual/html/pod/perlsec.html#Security_Bugs">setuid</a> (see <a href="install.html">install.html</a> for details) to run signup.cgi as the freeside user.
+ <li>Append the identity.pub from the freeside user on your freeside machine to the authorized_keys file of the newly created freeside user on the external machine(s).
+ <li>Run <pre>fs_signup_server <i>user</i> <i>machine</i> <i>agentnum</i> <i>refnum</i></pre> on the Freeside machine.
+ <ul>
+ <li><i>user</i> is a user from the mapsecrets file.
+ <li><i>machine</i> is the name of the external machine.
+ <li><i>agentnum</i> and <i>refnum</i> are the <a href="schema.html#agent">agent</a> and <a href="schema.html#part_referral">referral</a>, respectively, to use for customers who sign up via this signup server.
+ </ul>
+</ul>
+Optional:
+<ul>
+ <li>If you create a <b>/usr/local/freeside/ieak.template</b> file on the external machine, it will be sent to IE users with MIME type <i>application/x-Internet-signup</i>. This file will be processed with <a href="http://search.cpan.org/doc/MJD/Text-Template-1.23/Template.pm">Text::Template</a> with the following variables available:
+ <ul>
+ <li>$ac - area code of selected POP
+ <li>$exch - exchange of selected POP
+ <li>$loc - local part of selected POP
+ <li>$username
+ <li>$password
+ <li>$email_name - first and last name
+ </ul>
+ (an example file is included as <b>fs_signup/ieak.template</b>)
+ <li>If there are any entries in the <i>prepay_credit</i> table, a user can enter a string matching the <b>identifier</i> column to receive the credit specified in the <b>amount</b> column, after which that <b>identifier</b> is no longer valid. This can be used to implement pre-paid "calling card" type signups. The <i>bin/generate-prepay</i> script can be used to populate the <i>prepay_credit</i> table.
+</ul>
+</body>
diff --git a/htdocs/docs/trouble.html b/htdocs/docs/trouble.html
index 2cf6d4e71..fce743928 100644
--- a/htdocs/docs/trouble.html
+++ b/htdocs/docs/trouble.html
@@ -5,11 +5,6 @@
<h1>Troubleshooting</h1>
<ul>
<li>When troubleshooting the web interface, helpful information is often in your web server's error log.
- <li>Internet Explorer will not work with Freeside's HTML interface.
-<a HREF="http://www.netscape.com">Netscape</a>,
-<a HREF="http://lynx.browser.org">Lynx</a>, and
-<a HREF="http://www.cs.indiana.edu/elisp/w3/docs.html">Emacs/W3</a>,
-among others, should work fine.
<li>If bin/svc_acct.import fails with an "Out of memory!" error using MySQL, upgrede MySQL and recompile the Perl DBD. There was a memory leak in some older versions of MySQL.
<li>If you get tons of errors in your web server's error log like this:
<pre>
@@ -17,13 +12,6 @@ Ambiguous use of value => resolved to "value" =>
at /usr/lib/perl5/site_perl/File/CounterFile.pm line 132.
</pre>
This clutters up your log files but is otherwise harmless. Upgrade to the latest File::CounterFile.
- <li>If you get an Internal Server Error when adding or editing, but find that the update has occured, and you get something like the following in your web server's error log:
-<pre>
-access to <i>/your/path</i>/edit/process/<i>some_table</i>.cgi failed for
-<i>machine.domain.tld</i>, reason: malformed header from script.
-Bad header=HTTP/1.0 302 Moved Temporarily
-</pre>
- Then you forgot to apply this <a href="CGI-modules-2.76-patch.txt">patch</a> as mentioned in the <a href="install.html">New Installation</a> section of the documentation.
<li>If you get errors like this:
<pre>
UID.pm: Can't open /var/spool/freeside/conf/secrets: Permission denied
@@ -31,11 +19,8 @@ at <i>/your/path</i>/site_perl/FS/UID.pm line 26.
BEGIN failed--compilation aborted at
<i>/your/path</i>/edit/process/part_svc.cgi line 15.
</pre>
- Then the scripts are not running setuid freeside. If you were editing
-the files, it is possible you inadvertantly removed the setuid bit.
-As mentioned in the <a href="install.html">New Installation</a> section of the documentation, set ownership and permissions for the web interface. Your system should support secure setuid scripts or Perl's emulation, see <a href="http://www.perl.com/CPAN-local/doc/manual/html/pod/perlsec.html#Security_Bugs">perlsec: Security Bugs</a> for information and workarounds.
-<pre>cd /usr/local/apache/htdocs/freeside
-chown -R freeside .
-chmod 4755 browse/*.cgi edit/*.cgi edit/process/*.cgi misc/*.cgi misc/process/*.cgi search/*.cgi view/*.cgi</pre>
+ Then the scripts are not running as the freeside freeside user. See
+the <a href="install.html">New Installation</a> section of the documentation.
+ <li>If you receive `can not connect to server' errors using MySQL on a system that doesn't support native threading, you may need to specify the full hostname in your DBI datasource. See the <a href="http://www.mysql.com/Manual_chapter/manual_Problems.html#Can_not_connect_to_server">MySQL documentation</a>, DBI manpage and the DBD::mysql manpage for details.
</ul>
</body>
diff --git a/htdocs/docs/upgrade2.html b/htdocs/docs/upgrade2.html
index 4bf7ea45a..7acae48f7 100644
--- a/htdocs/docs/upgrade2.html
+++ b/htdocs/docs/upgrade2.html
@@ -1,8 +1,8 @@
<head>
- <title>Upgrading to 1.1.3</title>
+ <title>Upgrading to 1.1.4</title>
</head>
<body>
-<h1>Upgrading to 1.1.3 from 1.1.x</h1>
+<h1>Upgrading to 1.1.4 from 1.1.x</h1>
<ul>
<li>If migrating from 1.0.0, see these <a href="upgrade.html">instructions</a> first.
<li>Back up your data and current Freeside installation.
diff --git a/htdocs/docs/upgrade3.html b/htdocs/docs/upgrade3.html
new file mode 100644
index 000000000..0837e0207
--- /dev/null
+++ b/htdocs/docs/upgrade3.html
@@ -0,0 +1,40 @@
+<head>
+ <title>Upgrading to 1.2.x</title>
+</head>
+<body>
+<h1>Upgrading to 1.2.x from 1.1.x</h1>
+<ul>
+ <li>If migrating from 1.0.0, see these <a href="upgrade.html">instructions</a> first.
+ <li>If migrating from less than 1.1.4, see these <a href="upgrade2.html">instructions</a> first.
+ <li>Back up your data and current Freeside installation.
+ <li>Install the Perl module <a href="http://www.perl.com/CPAN/modules/by-module/String/">String-Approx</a>
+ <li><a href="config.html">Configuration file</a> location has changed!
+ <li>Move /var/spool/freeside/dbdef.<i>datasrc</i> to /usr/local/etc/freeside/dbdef.<i>datasrc</i>.
+ <li>Move /var/spool/freeside/counters to /usr/local/etc/freeside/counters.<i>datasrc</i>.
+ <li>Move /var/spool/freeside/export to /usr/local/etc/freeside/export.<i>datasrc</i>.
+ <li>Apply the following changes to your database:
+<pre>
+<!-- ALTER TABLE cust_main ADD middle varchar(80) NULL;
+ALTER TABLE cust_main ADD titlenum int NULL;
+-->ALTER TABLE cust_main CHANGE state state varchar(80) NULL;
+ALTER TABLE cust_main_county CHANGE state state varchar(80) NULL;
+ALTER TABLE cust_main_county ADD country char(2);
+ALTER TABLE cust_main CHANGE paydate paydate varchar(10);
+UPDATE cust_main SET country = "US" where country IS NULL OR country = '';
+UPDATE cust_main_county SET country = "US" where country IS NULL OR country = "";
+<!--CREATE TABLE part_title (
+ titlenum int NOT NULL,
+ title varchar(80) NOT NULL,
+ PRIMARY KEY (titlenum)
+);
+-->CREATE TABLE cust_main_invoice (
+ destnum int NOT NULL,
+ custnum int NOT NULL,
+ dest varchar(80) NOT NULL,
+ PRIMARY KEY (destnum),
+ INDEX ( custnum )
+);
+</pre>
+ <li>Run bin/dbdef-create. This file uses MySQL-specific syntax. If you are running a different database engine you will need to modify it slightly.
+ <li>Copy or symlink htdocs and site_perl to the new copies.
+</body>
diff --git a/htdocs/docs/upgrade4.html b/htdocs/docs/upgrade4.html
new file mode 100644
index 000000000..1d70f8b73
--- /dev/null
+++ b/htdocs/docs/upgrade4.html
@@ -0,0 +1,27 @@
+<head>
+ <title>Upgrading to 1.2.2</title>
+</head>
+<body>
+<h1>Upgrading to 1.2.2 from 1.2.x</h1>
+<ul>
+ <li>If migrating from 1.0.0, see these <a href="upgrade.html">instructions</a> first.
+ <li>If migrating from less than 1.1.4, see these <a href="upgrade2.html">instructions</a> first.
+ <li>If migrating from less than 1.2.0, see these <a href="upgrade3.html">instructions</a> first.
+ <li>Back up your data and current Freeside installation.
+ <li>Install the Perl modules <a href="http://www.perl.com/CPAN/modules/by-module/Locale/">Locale-Codes</a> and <a href="http://www.perl.com/CPAN/modules/by-module/Net/">Net-Whois</a>.
+ <li>Apply the following changes to your database:
+<pre>
+ALTER TABLE cust_pay_batch CHANGE exp exp VARCHAR(11);
+</pre>
+ <li>Copy or symlink htdocs to the new copy.
+ <li>Remove the symlink or directory <i>(your_site_perl_directory)</i>/FS.
+ <li>Change to the FS directory in the new tarball, and build and install the
+ Perl modules:
+ <pre>
+$ cd FS/
+$ perl Makefile.PL
+$ make
+$ su
+# make install</pre>
+ <li>Run bin/dbdef-create. This file uses MySQL-specific syntax. If you are running a different database engine you will need to modify it slightly.
+</body>
diff --git a/htdocs/docs/upgrade5.html b/htdocs/docs/upgrade5.html
new file mode 100644
index 000000000..fc4bf2c39
--- /dev/null
+++ b/htdocs/docs/upgrade5.html
@@ -0,0 +1,34 @@
+<head>
+ <title>Upgrading to 1.3.0</title>
+</head>
+<body>
+<h1>Upgrading to 1.3.0 from 1.2.2</h1>
+<ul>
+ <li>If migrating from 1.0.0, see these <a href="upgrade.html">instructions</a> first.
+ <li>If migrating from less than 1.1.4, see these <a href="upgrade2.html">instructions</a> first.
+ <li>If migrating from less than 1.2.0, see these <a href="upgrade3.html">instructions</a> first.
+ <li>If migrating from less than 1.2.2, see these <a href="upgrade4.html">instructions</a> first.
+ <li>Back up your data and current Freeside installation.
+ <li>Apply the following changes to your database:
+<pre>
+ALTER TABLE svc_acct_pop ADD loc CHAR(4);
+CREATE TABLE prepay_credit (
+ prepaynum int NOT NULL,
+ identifier varchar(80) NOT NULL,
+ amount decimal(10,2) NOT NULL,
+ PRIMARY KEY (prepaynum),
+ INDEX (identifier)
+);
+</pre>
+ <li>Copy or symlink htdocs to the new copy.
+ <li>Remove the symlink or directory <i>(your_site_perl_directory)</i>/FS.
+ <li>Change to the FS directory in the new tarball, and build and install the
+ Perl modules:
+ <pre>
+$ cd FS/
+$ perl Makefile.PL
+$ make
+$ su
+# make install</pre>
+ <li>Run bin/dbdef-create. This file uses MySQL-specific syntax. If you are running a different database engine you will need to modify it slightly.
+</body>
diff --git a/htdocs/edit/agent.cgi b/htdocs/edit/agent.cgi
index 5bd116528..5b42095b3 100755
--- a/htdocs/edit/agent.cgi
+++ b/htdocs/edit/agent.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# agent.cgi: Add/Edit agent (output form)
+# $Id: agent.cgi,v 1.7 1999-04-07 11:27:50 ivan Exp $
#
# ivan@sisd.com 97-dec-12
#
@@ -9,38 +9,70 @@
# bmccane@maxbaud.net 98-apr-3
#
# use FS::CGI, added inline documentation ivan@sisd.com 98-jul-12
+#
+# $Log: agent.cgi,v $
+# Revision 1.7 1999-04-07 11:27:50 ivan
+# avoid perl's silly arguement not numeric error
+#
+# Revision 1.6 1999/01/25 12:09:50 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:31 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:21 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/17 06:16:57 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.2 1998/11/23 07:52:08 ivan
+# *** empty log message ***
+#
use strict;
-use CGI::Base;
+use vars qw ( $cgi $agent $action $hashref $p $agent_type );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
+use FS::CGI qw(header menubar popurl);
+use FS::Record qw(qsearch qsearchs fields);
use FS::agent;
-use FS::CGI qw(header menubar);
+use FS::agent_type;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-
-my($agent,$action);
-if ( $cgi->var('QUERY_STRING') =~ /^(\d+)$/ ) { #editing
- $agent=qsearchs('agent',{'agentnum'=>$1});
- $action='Edit';
+if ( $cgi->param('error') ) {
+ $agent = new FS::agent ( {
+ map { $_, scalar($cgi->param($_)) } fields('agent')
+ } );
+} elsif ( $cgi->keywords ) {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $agent = qsearchs( 'agent', { 'agentnum' => $1 } );
} else { #adding
- $agent=create FS::agent {};
- $action='Add';
+ $agent = new FS::agent {};
}
-my($hashref)=$agent->hashref;
+$action = $agent->agentnum ? 'Edit' : 'Add';
+$hashref = $agent->hashref;
+
+$p = popurl(2);
+
+print $cgi->header( '-expires' => 'now' ), header("$action Agent", menubar(
+ 'Main Menu' => $p,
+ 'View all agents' => $p. 'browse/agent.cgi',
+));
-print header("$action Agent", menubar(
- 'Main Menu' => '../',
- 'View all agents' => '../browse/agent.cgi',
-)), '<FORM ACTION="process/agent.cgi" METHOD=POST>';
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-print qq!<INPUT TYPE="hidden" NAME="agentnum" VALUE="$hashref->{agentnum}">!,
+print '<FORM ACTION="', popurl(1), 'process/agent.cgi" METHOD=POST>',
+ qq!<INPUT TYPE="hidden" NAME="agentnum" VALUE="$hashref->{agentnum}">!,
"Agent #", $hashref->{agentnum} ? $hashref->{agentnum} : "(NEW)";
print <<END;
@@ -49,11 +81,10 @@ Agent <INPUT TYPE="text" NAME="agent" SIZE=32 VALUE="$hashre
Agent type <SELECT NAME="typenum" SIZE=1>
END
-my($agent_type);
foreach $agent_type (qsearch('agent_type',{})) {
- print "<OPTION";
+ print "<OPTION VALUE=". $agent_type->typenum;
print " SELECTED"
- if $hashref->{typenum} == $agent_type->getfield('typenum');
+ if $hashref->{typenum} && ( $hashref->{typenum} == $agent_type->typenum );
print ">", $agent_type->getfield('typenum'), ": ",
$agent_type->getfield('atype'),"\n";
}
diff --git a/htdocs/edit/agent_type.cgi b/htdocs/edit/agent_type.cgi
index b9fff4530..bdf64c58f 100755
--- a/htdocs/edit/agent_type.cgi
+++ b/htdocs/edit/agent_type.cgi
@@ -1,5 +1,7 @@
#!/usr/bin/perl -Tw
#
+# $Id: agent_type.cgi,v 1.11 1999-04-07 11:19:21 ivan Exp $
+#
# agent_type.cgi: Add/Edit agent type (output form)
#
# ivan@sisd.com 97-dec-10
@@ -9,46 +11,91 @@
# bmccane@maxbaud.net 98-apr-3
#
# use FS::CGI, added inline documentation ivan@sisd.com 98-jul-12
+#
+# $Log: agent_type.cgi,v $
+# Revision 1.11 1999-04-07 11:19:21 ivan
+# silly HTML typo
+#
+# Revision 1.10 1999/01/25 12:09:51 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.9 1999/01/19 05:13:32 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.8 1999/01/18 09:41:22 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.7 1999/01/18 09:22:29 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.6 1998/12/17 06:16:58 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.5 1998/11/21 07:58:27 ivan
+# package names link to them
+#
+# Revision 1.4 1998/11/21 07:45:19 ivan
+# visual, use FS::table_name when doing qsearch('table_name')
+#
+# Revision 1.3 1998/11/15 11:20:12 ivan
+# s/CGI-Base/CGI.pm/ causes s/QUERY_STRING/keywords/;
+#
+# Revision 1.2 1998/11/13 09:56:46 ivan
+# change configuration file layout to support multiple distinct databases (with
+# own set of config files, export, etc.)
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $agent_type $action $hashref $p $part_pkg );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
+use FS::Record qw(qsearch qsearchs fields);
use FS::agent_type;
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl);
+use FS::agent_type;
+use FS::part_pkg;
+use FS::type_pkgs;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-
-my($agent_type,$action);
-if ( $cgi->var('QUERY_STRING') =~ /^(\d+)$/ ) { #editing
+if ( $cgi->param('error') ) {
+ $agent_type = new FS::agent_type ( {
+ map { $_, scalar($cgi->param($_)) } fields('agent')
+ } );
+} elsif ( $cgi->keywords ) { #editing
+ my( $query ) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
$agent_type=qsearchs('agent_type',{'typenum'=>$1});
- $action='Edit';
} else { #adding
- $agent_type=create FS::agent_type {};
- $action='Add';
+ $agent_type = new FS::agent_type {};
}
-my($hashref)=$agent_type->hashref;
+$action = $agent_type->typenum ? 'Edit' : 'Add';
+$hashref = $agent_type->hashref;
+
+$p = popurl(2);
+print $cgi->header( '-expires' => 'now' ), header("$action Agent Type", menubar(
+ 'Main Menu' => "$p",
+ 'View all agent types' => "${p}browse/agent_type.cgi",
+));
-print header("$action Agent Type", menubar(
- 'Main Menu' => '../',
- 'View all agent types' => '../browse/agent_type.cgi',
-)), '<FORM ACTION="process/agent_type.cgi" METHOD=POST>';
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-print qq!<INPUT TYPE="hidden" NAME="typenum" VALUE="$hashref->{typenum}">!,
+print '<FORM ACTION="', popurl(1), 'process/agent_type.cgi" METHOD=POST>',
+ qq!<INPUT TYPE="hidden" NAME="typenum" VALUE="$hashref->{typenum}">!,
"Agent Type #", $hashref->{typenum} ? $hashref->{typenum} : "(NEW)";
print <<END;
-<BR>Type <INPUT TYPE="text" NAME="atype" SIZE=32 VALUE="$hashref->{atype}">
-<P>Select which packages agents of this type may sell to customers</P>
+<BR><BR>Agent Type <INPUT TYPE="text" NAME="atype" SIZE=32 VALUE="$hashref->{atype}">
+<BR><BR>Select which packages agents of this type may sell to customers<BR>
END
-my($part_pkg);
foreach $part_pkg ( qsearch('part_pkg',{}) ) {
print qq!<BR><INPUT TYPE="checkbox" NAME="pkgpart!,
$part_pkg->getfield('pkgpart'), qq!" !,
@@ -59,7 +106,9 @@ foreach $part_pkg ( qsearch('part_pkg',{}) ) {
})
? 'CHECKED '
: '',
- qq!"VALUE="ON"> !,$part_pkg->getfield('pkg')
+ qq!VALUE="ON"> !,
+ qq!<A HREF="${p}edit/part_pkg.cgi?!, $part_pkg->pkgpart,
+ '">', $part_pkg->getfield('pkg'), '</A>',
;
}
diff --git a/htdocs/edit/cust_credit.cgi b/htdocs/edit/cust_credit.cgi
index 75ef21208..35c4d48fe 100755
--- a/htdocs/edit/cust_credit.cgi
+++ b/htdocs/edit/cust_credit.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# cust_credit.cgi: Add a credit (output form)
+# $Id: cust_credit.cgi,v 1.7 1999-02-28 00:03:33 ivan Exp $
#
# Usage: cust_credit.cgi custnum [ -paybatch ]
# http://server.name/path/cust_credit?custnum [ -paybatch ]
#
-# Note: Should be run setuid root as user nobody.
-#
# some hooks in here for modifications as well as additions, but needs (lots) more work.
# also see process/cust_credit.cgi, the script that processes the form.
#
@@ -23,63 +21,89 @@
# ivan@voicenet.com 97-apr-21
#
# rewrite ivan@sisd.com 98-mar-16
+#
+# $Log: cust_credit.cgi,v $
+# Revision 1.7 1999-02-28 00:03:33 ivan
+# removed misleading comments
+#
+# Revision 1.6 1999/01/25 12:09:52 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:33 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:23 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/23 02:26:06 ivan
+# *** empty log message ***
+#
+# Revision 1.2 1998/12/17 06:16:59 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
use strict;
+use vars qw( $cgi $query $custnum $otaker $p1 $crednum $_date $amount $reason );
use Date::Format;
-use CGI::Base qw(:DEFAULT :CGI); #CGI module
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup getotaker);
+use FS::CGI qw(header popurl);
+use FS::Record qw(fields);
+#use FS::cust_credit;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
cgisuidsetup($cgi);
-#untaint custnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($custnum)=$1;
-
-#untaint otaker
-my($otaker)=getotaker;
-
-SendHeaders(); # one guess.
+if ( $cgi->param('error') ) {
+ #$cust_credit = new FS::cust_credit ( {
+ # map { $_, scalar($cgi->param($_)) } fields('cust_credit')
+ #} );
+ $custnum = $cgi->param('custnum');
+ $amount = $cgi->param('amount');
+ #$refund = $cgi->param('refund');
+ $reason = $cgi->param('reason');
+} else {
+ ($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $custnum = $1;
+ $amount = '';
+ #$refund = 'yes';
+ $reason = '';
+}
+$_date = time;
+
+$otaker = getotaker;
+
+$p1 = popurl(1);
+
+print $cgi->header( '-expires' => 'now' ), header("Post Credit", '');
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
print <<END;
-<HTML>
- <HEAD>
- <TITLE>Post Credit</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Post Credit</H1>
- </CENTER>
- <FORM ACTION="process/cust_credit.cgi" METHOD=POST>
- <HR><PRE>
+ <FORM ACTION="${p1}process/cust_credit.cgi" METHOD=POST>
+ <PRE>
END
-#crednum
-my($crednum)="";
+$crednum = "";
print qq!Credit #<B>!, $crednum ? $crednum : " <I>(NEW)</I>", qq!</B><INPUT TYPE="hidden" NAME="crednum" VALUE="$crednum">!;
-#custnum
print qq!\nCustomer #<B>$custnum</B><INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!;
-#paybatch
print qq!<INPUT TYPE="hidden" NAME="paybatch" VALUE="">!;
-#date
-my($date)=time;
-print qq!\nDate: <B>!, time2str("%D",$date), qq!</B><INPUT TYPE="hidden" NAME="_date" VALUE="$date">!;
+print qq!\nDate: <B>!, time2str("%D",$_date), qq!</B><INPUT TYPE="hidden" NAME="_date" VALUE="">!;
-#amount
-my($amount)='';
print qq!\nAmount \$<INPUT TYPE="text" NAME="amount" VALUE="$amount" SIZE=8 MAXLENGTH=8>!;
+print qq!<INPUT TYPE="hidden" NAME="credited" VALUE="">!;
-#refund?
-#print qq! <INPUT TYPE="checkbox" NAME="refund" VALUE="yes">Also post refund!;
+#print qq! <INPUT TYPE="checkbox" NAME="refund" VALUE="$refund">Also post refund!;
-#otaker (hidden)
print qq!<INPUT TYPE="hidden" NAME="otaker" VALUE="$otaker">!;
-#reason
-my($reason)='';
print qq!\nReason <INPUT TYPE="text" NAME="reason" VALUE="$reason" SIZE=72>!;
print <<END;
diff --git a/htdocs/edit/cust_main.cgi b/htdocs/edit/cust_main.cgi
index 14556010c..4eef9c74d 100755
--- a/htdocs/edit/cust_main.cgi
+++ b/htdocs/edit/cust_main.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# cust_main.cgi: Edit a customer (output form)
+# $Id: cust_main.cgi,v 1.24 2000-01-30 06:54:50 ivan Exp $
#
# Usage: cust_main.cgi custnum
# http://server.name/path/cust_main.cgi?custnum
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 96-nov-29 -> 96-dec-04
#
# Blank custnum for new customer.
@@ -38,82 +36,209 @@
# bmccane@maxbaud.net 98-apr-3
#
# fixed one missed day->daytime ivan@sisd.com 98-jul-13
+#
+# $Log: cust_main.cgi,v $
+# Revision 1.24 2000-01-30 06:54:50 ivan
+# credit card expiration dates not sticky bug fixed?
+#
+# Revision 1.23 2000/01/27 00:53:14 ivan
+# 5.004_04 workaround
+#
+# Revision 1.22 1999/12/17 02:33:23 ivan
+# argh
+#
+# Revision 1.21 1999/08/23 07:40:38 ivan
+# missing </TD> flag
+#
+# Revision 1.20 1999/08/23 07:08:11 ivan
+# no CGI::Switch for now
+#
+# Revision 1.19 1999/08/21 02:14:25 ivan
+# better error message for no agents
+#
+# Revision 1.18 1999/08/11 15:38:33 ivan
+# fix for perl 5.004_04
+#
+# Revision 1.17 1999/08/10 11:15:45 ivan
+# corrected a misleading comment
+#
+# Revision 1.15 1999/04/14 13:14:54 ivan
+# configuration option to edit referrals of existing customers
+#
+# Revision 1.14 1999/04/14 07:47:53 ivan
+# i18n fixes
+#
+# Revision 1.13 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.12 1999/04/06 11:16:16 ivan
+# give a meaningful error message if you try to create a customer before you've
+# created an agent
+#
+# Revision 1.11 1999/03/25 13:55:10 ivan
+# one-screen new customer entry (including package and service) for simple
+# packages with one svc_acct service
+#
+# Revision 1.10 1999/02/28 00:03:34 ivan
+# removed misleading comments
+#
+# Revision 1.9 1999/02/23 08:09:20 ivan
+# beginnings of one-screen new customer entry and some other miscellania
+#
+# Revision 1.8 1999/01/25 12:09:53 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.7 1999/01/19 05:13:34 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 09:41:24 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.5 1999/01/18 09:22:30 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.4 1998/12/23 08:08:15 ivan
+# fix typo
+#
+# Revision 1.3 1998/12/17 06:17:00 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $custnum $action $cust_main $p1 @agents $agentnum
+ $last $first $ss $company $address1 $address2 $city $zip
+ $daytime $night $fax @invoicing_list $invoicing_list $payinfo
+ $payname %payby %paybychecked $refnum $otaker $r );
+use vars qw ( $conf $pkgpart $username $password $popnum $ulen $ulen2 );
+#use CGI::Switch;
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup getotaker);
-use FS::Record qw(qsearch qsearchs);
+#use FS::Record qw(qsearch qsearchs fields);
+use FS::Record qw(qsearch qsearchs fields dbdef);
+use FS::CGI qw(header popurl itable table);
use FS::cust_main;
+use FS::agent;
+use FS::part_referral;
+use FS::cust_main_county;
+
+ #for misplaced logic below
+ use FS::part_pkg;
-my($cgi) = new CGI::Base;
-$cgi->get;
+ #for false laziness below
+ use FS::svc_acct_pop;
+ #for (other) false laziness below
+ use FS::agent;
+ use FS::type_pkgs;
+
+$cgi = new CGI;
cgisuidsetup($cgi);
-SendHeaders(); # one guess.
+$conf = new FS::Conf;
#get record
-my($custnum,$action,$cust_main);
-if ( $cgi->var('QUERY_STRING') =~ /^(\d+)$/ ) { #editing
+
+if ( $cgi->param('error') ) {
+ $cust_main = new FS::cust_main ( {
+ map { $_, scalar($cgi->param($_)) } fields('cust_main')
+ } );
+ $custnum = $cust_main->custnum;
+ $pkgpart = $cgi->param('pkgpart_svcpart') || '';
+ if ( $pkgpart =~ /^(\d+)_/ ) {
+ $pkgpart = $1;
+ } else {
+ $pkgpart = '';
+ }
+ $username = $cgi->param('username');
+ $password = $cgi->param('_password');
+ $popnum = $cgi->param('popnum');
+} elsif ( $cgi->keywords ) { #editing
+ my( $query ) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
$custnum=$1;
- $cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
- $action='Edit';
+ $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
+ $pkgpart = 0;
+ $username = '';
+ $password = '';
+ $popnum = 0;
} else {
$custnum='';
- $cust_main = create FS::cust_main ( {} );
+ $cust_main = new FS::cust_main ( {} );
$cust_main->setfield('otaker',&getotaker);
- $cust_main->setfield('country','US');
- $action='Add';
+ $pkgpart = 0;
+ $username = '';
+ $password = '';
+ $popnum = 0;
}
-
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Customer $action</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Customer $action</H1>
- </CENTER>
- <FORM ACTION="process/cust_main.cgi" METHOD=POST>
- <PRE>
-END
-
-print qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!,
- qq!Customer #<FONT SIZE="+1"><B>!;
-print $custnum ? $custnum : " (NEW)" , "</B></FONT>";
-
-#agentnum
-my($agentnum)=$cust_main->agentnum || 1; #set to first agent by default
-my(@agents) = qsearch('agent',{});
-print qq!\n\nAgent # <SELECT NAME="agentnum" SIZE="1">!;
-my($agent);
-foreach $agent (sort {
- $a->agent cmp $b->agent;
-} @agents) {
- print "<OPTION" . " SELECTED"x($agent->agentnum==$agentnum),
- ">", $agent->agentnum,": ", $agent->agent, "\n";
+$action = $custnum ? 'Edit' : 'Add';
+
+# top
+
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("Customer $action", '');
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+print qq!<FORM ACTION="${p1}process/cust_main.cgi" METHOD=POST>!,
+ qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!,
+ qq!Customer # !, ( $custnum ? $custnum : " (NEW)" ),
+
+;
+
+# agent
+
+$r = qq!<font color="#ff0000">*</font>!;
+
+@agents = qsearch( 'agent', {} );
+#die "No agents created!" unless @agents;
+die "You have not created any agents. You must create at least one agent before adding a customer. Go to ". popurl(2). "browse/agent.cgi and create one or more agents." unless @agents;
+$agentnum = $cust_main->agentnum || $agents[0]->agentnum; #default to first
+if ( scalar(@agents) == 1 ) {
+ print qq!<INPUT TYPE="hidden" NAME="agentnum" VALUE="$agentnum">!;
+} else {
+ print qq!<BR><BR>${r}Agent <SELECT NAME="agentnum" SIZE="1">!;
+ my $agent;
+ foreach $agent (sort {
+ $a->agent cmp $b->agent;
+ } @agents) {
+ print '<OPTION VALUE="', $agent->agentnum, '"',
+ " SELECTED"x($agent->agentnum==$agentnum),
+ ">", $agent->agentnum,": ", $agent->agent;
+ }
+ print "</SELECT>";
}
-print "</SELECT>";
#referral
-#unless ($custnum) {
- my($refnum)=$cust_main->refnum || 0; #to avoid "arguement not numeric" error
+
+$refnum = $cust_main->refnum || 0;
+if ( $custnum && ! $conf->exists('editreferrals') ) {
+ print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$refnum">!;
+} else {
my(@referrals) = qsearch('part_referral',{});
- print qq!\nReferral <SELECT NAME="refnum" SIZE="1">!;
- print "<OPTION> \n";
- my($referral);
- foreach $referral (sort {
- $a->refnum <=> $b->refnum;
- } @referrals) {
- print "<OPTION" . " SELECTED"x($referral->refnum==$refnum),
- ">", $referral->refnum, ": ", $referral->referral,"\n";
+ if ( scalar(@referrals) == 1 ) {
+ $refnum ||= $referrals[0]->refnum;
+ print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$refnum">!;
+ } else {
+ print qq!<BR><BR>${r}Referral <SELECT NAME="refnum" SIZE="1">!;
+ print "<OPTION> " unless $refnum;
+ my($referral);
+ foreach $referral (sort {
+ $a->refnum <=> $b->refnum;
+ } @referrals) {
+ print "<OPTION" . " SELECTED"x($referral->refnum==$refnum),
+ ">", $referral->refnum, ": ", $referral->referral;
+ }
+ print "</SELECT>";
}
- print "</SELECT>";
-#}
+}
-my($last,$first,$ss,$company,$address1,$address2,$city)=(
+
+# contact info
+
+($last,$first,$ss,$company,$address1,$address2,$city,$zip)=(
$cust_main->last,
$cust_main->first,
$cust_main->ss,
@@ -121,94 +246,190 @@ my($last,$first,$ss,$company,$address1,$address2,$city)=(
$cust_main->address1,
$cust_main->address2,
$cust_main->city,
+ $cust_main->zip,
);
-print <<END;
-
-
-Name (last)<INPUT TYPE="text" NAME="last" VALUE="$last"> (first)<INPUT TYPE="text" NAME="first" VALUE="$first"> SS# <INPUT TYPE="text" NAME="ss" VALUE="$ss" SIZE=11 MAXLENGTH=11>
-Company <INPUT TYPE="text" NAME="company" VALUE="$company">
-Address <INPUT TYPE="text" NAME="address1" VALUE="$address1" SIZE=40 MAXLENGTH=40>
- <INPUT TYPE="text" NAME="address2" VALUE="$address2" SIZE=40 MAXLENGTH=40>
-City <INPUT TYPE="text" NAME="city" VALUE="$city"> State (county) <SELECT NAME="state" SIZE="1">
+print "<BR><BR>Contact information", &itable("#c0c0c0"), <<END;
+<TR><TH ALIGN="right">${r}Contact name<BR>(last, first)</TH><TD COLSPAN=3><INPUT TYPE="text" NAME="last" VALUE="$last">, <INPUT TYPE="text" NAME="first" VALUE="$first"></TD><TD ALIGN="right">SS#</TD><TD><INPUT TYPE="text" NAME="ss" VALUE="$ss" SIZE=11></TD></TR>
+<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="company" VALUE="$company" SIZE=70></TD></TR>
+<TR><TH ALIGN="right">${r}Address</TH><TD COLSPAN=5><INPUT TYPE="text" NAME="address1" VALUE="$address1" SIZE=70></TD></TR>
+<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="address2" VALUE="$address2" SIZE=70></TD></TR>
+<TR><TH ALIGN="right">${r}City</TH><TD><INPUT TYPE="text" NAME="city" VALUE="$city"></TD><TH ALIGN="right">${r}State/Country</TH><TD><SELECT NAME="state" SIZE="1">
END
+$cust_main->country('US') unless $cust_main->country; #eww
foreach ( qsearch('cust_main_county',{}) ) {
print "<OPTION";
print " SELECTED" if ( $cust_main->state eq $_->state
- && $cust_main->county eq $_->county );
+ && $cust_main->county eq $_->county
+ && $cust_main->country eq $_->country
+ );
print ">",$_->state;
print " (",$_->county,")" if $_->county;
+ print " / ", $_->country;
}
-print "</SELECT>";
+print qq!</SELECT></TD><TH>${r}Zip</TH><TD><INPUT TYPE="text" NAME="zip" VALUE="$zip" SIZE=10></TD></TR>!;
-my($zip,$country,$daytime,$night,$fax)=(
- $cust_main->zip,
- $cust_main->country,
+($daytime,$night,$fax)=(
$cust_main->daytime,
$cust_main->night,
$cust_main->fax,
);
print <<END;
- Zip <INPUT TYPE="text" NAME="zip" VALUE="$zip" SIZE=10 MAXLENGTH=10>
-Country: <FONT SIZE="+1"><B>$country</B></FONT><INPUT TYPE="hidden" NAME="country" VALUE="$country">
+<TR><TD ALIGN="right">Day Phone</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="$daytime" SIZE=18></TD></TR>
+<TR><TD ALIGN="right">Night Phone</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="$night" SIZE=18></TD></TR>
+<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="$fax" SIZE=12></TD></TR>
+END
-Phone (daytime)<INPUT TYPE="text" NAME="daytime" VALUE="$daytime" SIZE=18 MAXLENGTH=20> (night)<INPUT TYPE="text" NAME="night" VALUE="$night" SIZE=18 MAXLENGTH=20> (fax)<INPUT TYPE="text" NAME="fax" VALUE="$fax" SIZE=12 MAXLENGTH=12>
+print "</TABLE>$r required fields<BR>";
+
+# billing info
+
+sub expselect {
+ my $prefix = shift;
+ my( $m, $y ) = (0, 0);
+ if ( scalar(@_) ) {
+ my $date = shift;
+ if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format
+ ( $m, $y ) = ( $2, $1 );
+ } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) {
+ ( $m, $y ) = ( $1, $3 );
+ } else {
+ die "unrecognized expiration date format: $date";
+ }
+ }
-END
+ my $return = qq!<SELECT NAME="$prefix!. qq!_month" SIZE="1">!;
+ for ( 1 .. 12 ) {
+ $return .= "<OPTION";
+ $return .= " SELECTED" if $_ == $m;
+ $return .= ">$_";
+ }
+ $return .= qq!</SELECT>/<SELECT NAME="$prefix!. qq!_year" SIZE="1">!;
+ for ( 1999 .. 2037 ) {
+ $return .= "<OPTION";
+ $return .= " SELECTED" if $_ == $y;
+ $return .= ">$_";
+ }
+ $return .= "</SELECT>";
-my(%payby)=(
- 'CARD' => "Credit card ",
- 'BILL' => "Billing ",
- 'COMP' => "Complimentary",
-);
-for (qw(CARD BILL COMP)) {
- print qq!<INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
- print qq! CHECKED! if ($cust_main->payby eq "$_");
- print qq!>$payby{$_}!;
+ $return;
}
-
-my($payinfo,$payname,$otaker)=(
+print "<BR>Billing information", &itable("#c0c0c0"),
+ qq!<TR><TD><INPUT TYPE="checkbox" NAME="tax" VALUE="Y"!;
+print qq! CHECKED! if $cust_main->tax eq "Y";
+print qq!>Tax Exempt</TD></TR>!;
+print qq!<TR><TD><INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"!;
+@invoicing_list = $cust_main->invoicing_list;
+print qq! CHECKED!
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+print qq!>Postal mail invoice</TD></TR>!;
+$invoicing_list = join(', ', grep { $_ ne 'POST' } @invoicing_list );
+print qq!<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="$invoicing_list"></TD></TR>!;
+
+print "<TR><TD>Billing type</TD></TR>",
+ "</TABLE>",
+ &table("#c0c0c0"), "<TR>";
+
+($payinfo, $payname)=(
$cust_main->payinfo,
$cust_main->payname,
- $cust_main->otaker,
);
-my($paydate);
-if ( $cust_main->paydate =~ /^(\d{4})-(\d{2})-\d{2}$/ ) {
- $paydate="$2/$1"
-} elsif ( $cust_main->paydate =~ /^(\d{2})-\d{2}-(\d{4}$)/ ) {
- $paydate="$1/$2"
-}
-else {
- $paydate='';
+%payby = (
+ 'CARD' => qq!Credit card<BR>${r}<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR>${r}Exp !. expselect("CARD"). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR>${r}Exp !. expselect("BILL", "12-2037"). qq!<BR>${r}Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR>${r}Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR>${r}Exp !. expselect("COMP"),
+);
+%paybychecked = (
+ 'CARD' => qq!Credit card<BR>${r}<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR>${r}Exp !. expselect("CARD", $cust_main->paydate). qq!<BR>${r}Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR>${r}Exp !. expselect("BILL", $cust_main->paydate). qq!<BR>${r}Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR>${r}Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR>${r}Exp !. expselect("COMP", $cust_main->paydate),
+);
+for (qw(CARD BILL COMP)) {
+ print qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($cust_main->payby eq "$_") {
+ print qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ print qq!> $payby{$_}</TD>!;
+ }
}
-print <<END;
-
- Card number , P.O. # or Authorization <INPUT TYPE="text" NAME="payinfo" VALUE="$payinfo" SIZE=19 MAXLENGTH=19>
-END
-
-print qq!Exp. date (MM/YY or MM/YYYY)<INPUT TYPE="text" NAME="paydate" VALUE="$paydate" SIZE=8 MAXLENGTH=7> Billing name <INPUT TYPE="text" NAME="payname" VALUE="$payname">\n<INPUT TYPE="checkbox" NAME="tax" VALUE="Y"!;
-print qq! CHECKED! if $cust_main->tax eq "Y";
-print qq!> Tax Exempt!;
-
-print <<END;
-
-
-Order taken by: <FONT SIZE="+1"><B>$otaker</B></FONT><INPUT TYPE="hidden" NAME="otaker" VALUE="$otaker">
-</PRE>
+print "</TR></TABLE>$r required fields for each billing type";
+
+unless ( $custnum ) {
+ # pry the wrong place for this logic. also pretty expensive
+ #use FS::part_pkg;
+
+ #false laziness, copied from FS::cust_pkg::order
+ my $pkgpart;
+ if ( scalar(@agents) == 1 ) {
+ # $pkgpart->{PKGPART} is true iff $custnum may purchase $pkgpart
+ my($agent)=qsearchs('agent',{'agentnum'=> $agentnum });
+ $pkgpart = $agent->pkgpart_hashref;
+ } else {
+ #can't know (agent not chosen), so, allow all
+ my %typenum;
+ foreach my $agent ( @agents ) {
+ next if $typenum{$agent->typenum}++;
+ #fixed in 5.004_05 #$pkgpart->{$_}++ foreach keys %{ $agent->pkgpart_hashref }
+ foreach ( keys %{ $agent->pkgpart_hashref } ) { $pkgpart->{$_}++; } #5.004_04 workaround
+ }
+ }
+ #eslaf
+
+ my @part_pkg = grep { $_->svcpart('svc_acct') && $pkgpart->{ $_->pkgpart } }
+ qsearch( 'part_pkg', {} );
+
+ if ( @part_pkg ) {
+
+ print "<BR><BR>First package", &itable("#c0c0c0"),
+ qq!<TR><TD COLSPAN=2><SELECT NAME="pkgpart_svcpart">!;
+
+ print qq!<OPTION VALUE="">(none)!;
+
+ foreach my $part_pkg ( @part_pkg ) {
+ print qq!<OPTION VALUE="!,
+# $part_pkg->pkgpart. "_". $pkgpart{ $part_pkg->pkgpart }, '"';
+ $part_pkg->pkgpart. "_". $part_pkg->svcpart, '"';
+ print " SELECTED" if $pkgpart && ( $part_pkg->pkgpart == $pkgpart );
+ print ">", $part_pkg->pkg, " - ", $part_pkg->comment;
+ }
+ print "</SELECT></TD></TR>";
+
+ #false laziness: (mostly) copied from edit/svc_acct.cgi
+ #$ulen = $svc_acct->dbdef_table->column('username')->length;
+ $ulen = dbdef->table('svc_acct')->column('username')->length;
+ $ulen2 = $ulen+2;
+ print <<END;
+<TR><TD ALIGN="right">Username</TD>
+<TD><INPUT TYPE="text" NAME="username" VALUE="$username" SIZE=$ulen2 MAXLENGTH=$ulen></TD></TR>
+<TR><TD ALIGN="right">Password</TD>
+<TD><INPUT TYPE="text" NAME="_password" VALUE="$password" SIZE=10 MAXLENGTH=8>
+(blank to generate)</TD></TR>
END
+ print qq!<TR><TD ALIGN="right">POP</TD><TD><SELECT NAME="popnum" SIZE=1><OPTION> !;
+ my($svc_acct_pop);
+ foreach $svc_acct_pop ( qsearch ('svc_acct_pop',{} ) ) {
+ print qq!<OPTION VALUE="!, $svc_acct_pop->popnum, '"',
+ ( $popnum && $svc_acct_pop->popnum == $popnum ) ? ' SELECTED' : '', ">",
+ $svc_acct_pop->popnum, ": ",
+ $svc_acct_pop->city, ", ",
+ $svc_acct_pop->state,
+ " (", $svc_acct_pop->ac, ")/",
+ $svc_acct_pop->exch, "\n"
+ ;
+ }
+ print "</SELECT></TD></TR></TABLE>";
+ }
+}
-print qq!<CENTER><INPUT TYPE="submit" VALUE="!,
- $custnum ? "Apply Changes" : "Add Customer", qq!"></CENTER>!;
-
-print <<END;
-
- </FORM>
- </BODY>
-</HTML>
-END
+$otaker = $cust_main->otaker;
+print qq!<INPUT TYPE="hidden" NAME="otaker" VALUE="$otaker">!,
+ qq!<BR><BR><INPUT TYPE="submit" VALUE="!,
+ $custnum ? "Apply Changes" : "Add Customer", qq!">!,
+ "</FORM></BODY></HTML>",
+;
diff --git a/htdocs/edit/cust_main_county-expand.cgi b/htdocs/edit/cust_main_county-expand.cgi
index 59ff7043a..783e92826 100755
--- a/htdocs/edit/cust_main_county-expand.cgi
+++ b/htdocs/edit/cust_main_county-expand.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# cust_main_county-expand.cgi: Expand a state into counties (output form)
+# $Id: cust_main_county-expand.cgi,v 1.6 1999-01-25 12:09:54 ivan Exp $
#
# ivan@sisd.com 97-dec-16
#
@@ -8,39 +8,78 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: cust_main_county-expand.cgi,v $
+# Revision 1.6 1999-01-25 12:09:54 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:35 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:25 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/17 06:17:01 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.2 1998/11/18 09:01:38 ivan
+# i18n! i18n!
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $taxnum $cust_main_county $p1 $delim $expansion );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl);
+use FS::cust_main_county;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-
-$cgi->var('QUERY_STRING') =~ /^(\d+)$/
- or die "Illegal taxnum!";
-my($taxnum)=$1;
+if ( $cgi->param('error') ) {
+ $taxnum = $cgi->param('taxnum');
+ $delim = $cgi->param('delim');
+ $expansion = $cgi->param('expansion');
+} else {
+ my ($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/
+ or die "Illegal taxnum!";
+ $taxnum = $1;
+ $delim = 'n';
+ $expansion = '';
+}
-my($cust_main_county)=qsearchs('cust_main_county',{'taxnum'=>$taxnum});
+$cust_main_county = qsearchs('cust_main_county',{'taxnum'=>$taxnum});
die "Can't expand entry!" if $cust_main_county->getfield('county');
-print header("Tax Rate (expand state)", menubar(
- 'Main Menu' => '../',
-)), <<END;
- <FORM ACTION="process/cust_main_county-expand.cgi" METHOD=POST>
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("Tax Rate (expand)", menubar(
+ 'Main Menu' => popurl(2),
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print <<END;
+ <FORM ACTION="${p1}process/cust_main_county-expand.cgi" METHOD=POST>
<INPUT TYPE="hidden" NAME="taxnum" VALUE="$taxnum">
- Separate counties by
- <INPUT TYPE="radio" NAME="delim" VALUE="n" CHECKED>line
- (rumor has it broken on some browsers) or
- <INPUT TYPE="radio" NAME="delim" VALUE="s">whitespace.
+ Separate by
+END
+print '<INPUT TYPE="radio" NAME="delim" VALUE="n"';
+print ' CHECKED' if $delim eq 'n';
+print '>line (rumor has it broken on some browsers) or',
+ '<INPUT TYPE="radio" NAME="delim" VALUE="s"';
+print ' CHECKED' if $delim eq 's';
+print '>whitespace.';
+print <<END;
<BR><INPUT TYPE="submit" VALUE="Submit">
- <BR><TEXTAREA NAME="counties" ROWS=100></TEXTAREA>
+ <BR><TEXTAREA NAME="expansion" ROWS=100>$expansion</TEXTAREA>
</FORM>
</CENTER>
</BODY>
diff --git a/htdocs/edit/cust_main_county.cgi b/htdocs/edit/cust_main_county.cgi
index 904d58346..747a63df6 100755
--- a/htdocs/edit/cust_main_county.cgi
+++ b/htdocs/edit/cust_main_county.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# cust_main_county.cgi: Edit tax rates (output form)
+# $Id: cust_main_county.cgi,v 1.8 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 97-dec-13-16
#
@@ -9,41 +9,75 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: cust_main_county.cgi,v $
+# Revision 1.8 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.7 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.6 1999/01/25 12:09:55 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:36 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:26 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/17 06:17:02 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.2 1998/11/18 09:01:39 ivan
+# i18n! i18n!
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $cust_main_county );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl table);
+use FS::cust_main_county;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
+print $cgi->header( '-expires' => 'now' ), header("Edit tax rates", menubar(
+ 'Main Menu' => popurl(2),
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-print header("Edit tax rates", menubar(
- 'Main Menu' => '../',
-)),<<END;
- <FORM ACTION="process/cust_main_county.cgi" METHOD=POST>
- <TABLE BORDER>
+print qq!<FORM ACTION="!, popurl(1),
+ qq!process/cust_main_county.cgi" METHOD=POST>!, &table(), <<END;
<TR>
+ <TH><FONT SIZE=-1>Country</FONT></TH>
<TH><FONT SIZE=-1>State</FONT></TH>
<TH>County</TH>
<TH><FONT SIZE=-1>Tax</FONT></TH>
</TR>
END
-my($cust_main_county);
foreach $cust_main_county ( qsearch('cust_main_county',{}) ) {
my($hashref)=$cust_main_county->hashref;
print <<END;
<TR>
- <TD>$hashref->{state}</TD>
+ <TD>$hashref->{country}</TD>
END
+ print "<TD>", $hashref->{state}
+ ? $hashref->{state}
+ : '(ALL)'
+ , "</TD>";
+
print "<TD>", $hashref->{county}
? $hashref->{county}
: '(ALL)'
diff --git a/htdocs/edit/cust_pay.cgi b/htdocs/edit/cust_pay.cgi
index a6cb204d1..5dee76ed9 100755
--- a/htdocs/edit/cust_pay.cgi
+++ b/htdocs/edit/cust_pay.cgi
@@ -1,61 +1,82 @@
#!/usr/bin/perl -Tw
#
-# cust_pay.cgi: Add a payment (output form)
+# $Id: cust_pay.cgi,v 1.6 1999-02-28 00:03:35 ivan Exp $
#
# Usage: cust_pay.cgi invnum
# http://server.name/path/cust_pay.cgi?invnum
#
-# Note: Should be run setuid as user nobody.
-#
# some hooks for modifications as well as additions, but needs work.
#
# ivan@voicenet.com 96-dec-11
#
# rewrite ivan@sisd.com 98-mar-16
+#
+# $Log: cust_pay.cgi,v $
+# Revision 1.6 1999-02-28 00:03:35 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/01/25 12:09:56 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.4 1999/01/19 05:13:37 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1999/01/18 09:41:27 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.2 1998/12/17 06:17:03 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
use strict;
+use vars qw( $cgi $invnum $p1 $_date $payby $payinfo $paid );
use Date::Format;
-use CGI::Base qw(:DEFAULT :CGI);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(header popurl);
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
cgisuidsetup($cgi);
-#untaint invnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($invnum)=$1;
+if ( $cgi->param('error') ) {
+ $invnum = $cgi->param('invnum');
+ $paid = $cgi->param('paid');
+ $payby = $cgi->param('payby');
+ $payinfo = $cgi->param('payinfo');
+} else {
+ my ($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $invnum = $1;
+ $paid = '';
+ $payby = "BILL";
+ $payinfo = "";
+}
+$_date = time;
+
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("Enter payment", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-SendHeaders(); # one guess.
print <<END;
-<HTML>
- <HEAD>
- <TITLE>Enter payment</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Enter payment</H1>
- </CENTER>
- <FORM ACTION="process/cust_pay.cgi" METHOD=POST>
+ <FORM ACTION="${p1}process/cust_pay.cgi" METHOD=POST>
<HR><PRE>
END
-#invnum
print qq!Invoice #<B>$invnum</B><INPUT TYPE="hidden" NAME="invnum" VALUE="$invnum">!;
-#date
-my($date)=time;
-print qq!<BR>Date: <B>!, time2str("%D",$date), qq!</B><INPUT TYPE="hidden" NAME="_date" VALUE="$date">!;
+print qq!<BR>Date: <B>!, time2str("%D",$_date), qq!</B><INPUT TYPE="hidden" NAME="_date" VALUE="$_date">!;
-#paid
-print qq!<BR>Amount \$<INPUT TYPE="text" NAME="paid" VALUE="" SIZE=8 MAXLENGTH=8>!;
+print qq!<BR>Amount \$<INPUT TYPE="text" NAME="paid" VALUE="$paid" SIZE=8 MAXLENGTH=8>!;
-#payby
-my($payby)="BILL";
print qq!<BR>Payby: <B>$payby</B><INPUT TYPE="hidden" NAME="payby" VALUE="$payby">!;
#payinfo (check # now as payby="BILL" hardcoded.. what to do later?)
-my($payinfo)="";
print qq!<BR>Check #<INPUT TYPE="text" NAME="payinfo" VALUE="$payinfo">!;
#paybatch
@@ -64,7 +85,7 @@ print qq!<INPUT TYPE="hidden" NAME="paybatch" VALUE="">!;
print <<END;
</PRE>
<BR>
-<CENTER><INPUT TYPE="submit" VALUE="Post"></CENTER>
+<INPUT TYPE="submit" VALUE="Post payment">
END
print <<END;
diff --git a/htdocs/edit/cust_pkg.cgi b/htdocs/edit/cust_pkg.cgi
index d7f143db4..b3c92249f 100755
--- a/htdocs/edit/cust_pkg.cgi
+++ b/htdocs/edit/cust_pkg.cgi
@@ -1,14 +1,12 @@
#!/usr/bin/perl -Tw
#
-# cust_pkg.cgi: Add/edit packages (output form)
+# $Id: cust_pkg.cgi,v 1.8 1999-07-21 07:34:13 ivan Exp $
#
# this is for changing packages around, not editing things within the package
#
# Usage: cust_pkg.cgi custnum
# http://server.name/path/cust_pkg.cgi?custnum
#
-# Note: Should be run setuid freeside as user nobody
-#
# started with /sales/add/cust_pkg.cgi, which added packages
# ivan@voicenet.com 97-jan-5, 97-mar-21
#
@@ -23,66 +21,93 @@
#
# fixed a pretty cool bug from above which caused a visual glitch ivan@sisd.com
# 98-jun-1
+#
+# $Log: cust_pkg.cgi,v $
+# Revision 1.8 1999-07-21 07:34:13 ivan
+# links to package browse and agent type edit if there aren't any packages to
+# order. thanks to "Tech Account" <techy@orac.hq.org>
+#
+# Revision 1.7 1999/04/14 01:03:01 ivan
+# oops, in 1.2 tree, can't do searches until [cgi|admin]suidsetup,
+# bug is hidden by mod_perl persistance
+#
+# Revision 1.6 1999/02/28 00:03:36 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/02/07 09:59:18 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.4 1999/01/19 05:13:38 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1999/01/18 09:41:28 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.2 1998/12/17 06:17:04 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use vars qw( $cgi %pkg %comment $custnum $p1 @cust_pkg
+ $cust_main $agent $type_pkgs $count %remove_pkg $pkgparts );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
-use FS::UID qw(cgisuidsetup getotaker);
+use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearch qsearchs);
+use FS::CGI qw(header popurl);
+use FS::part_pkg;
+use FS::type_pkgs;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-my(%pkg,%comment);
+%pkg = ();
+%comment = ();
foreach (qsearch('part_pkg', {})) {
$pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg');
$comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment');
}
-#untaint custnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($custnum)=$1;
+if ( $cgi->param('error') ) {
+ $custnum = $cgi->param('custnum');
+ %remove_pkg = map { $_ => 1 } $cgi->param('remove_pkg');
+} else {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $custnum = $1;
+ undef %remove_pkg;
+}
-my($otaker)=&getotaker;
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("Add/Edit Packages", '');
-SendHeaders();
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Add/Edit Packages</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Add/Edit Packages</H1>
- </CENTER>
- <FORM ACTION="process/cust_pkg.cgi" METHOD=POST>
- <HR>
-END
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-#custnum
-print qq!<INPUT TYPE="hidden" NAME="new_custnum" VALUE="$custnum">!;
+print qq!<FORM ACTION="${p1}process/cust_pkg.cgi" METHOD=POST>!;
-#current packages (except cancelled packages)
-my(@cust_pkg) = grep ! $_->getfield('cancel'),
- qsearch('cust_pkg',{'custnum'=>$custnum});
+print qq!<INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">!;
+
+#current packages
+@cust_pkg = qsearch('cust_pkg',{ 'custnum' => $custnum, 'cancel' => '' } );
if (@cust_pkg) {
print <<END;
-<CENTER><FONT SIZE="+2">Current packages</FONT></CENTER>
-These are packages the customer currently has. Select those packages you
-wish to remove (if any).<BR><BR>
+Current packages - select to remove (services are moved to a new package below)
+<BR><BR>
END
my ($count) = 0 ;
- print qq!<CENTER><TABLE>! ;
+ print qq!<TABLE>! ;
foreach (@cust_pkg) {
- print qq!<TR>! if ($count ==0) ;
+ print '<TR>' if $count == 0;
my($pkgnum,$pkgpart)=( $_->getfield('pkgnum'), $_->getfield('pkgpart') );
- print qq!<TD><INPUT TYPE="checkbox" NAME="remove_pkg" VALUE="$pkgnum">!,
- #qq!$pkgnum: $pkg{$pkgpart} - $comment{$pkgpart}</TD>\n!,
- #now you've got to admit this bug was pretty cool
- qq!$pkgnum: $pkg{$pkgpart} - $comment{$pkgpart}</TD>\n!;
+ print qq!<TD><INPUT TYPE="checkbox" NAME="remove_pkg" VALUE="$pkgnum"!;
+ print " CHECKED" if $remove_pkg{$pkgnum};
+ print qq!>$pkgnum: $pkg{$pkgpart} - $comment{$pkgpart}</TD>\n!;
$count ++ ;
if ($count == 2)
{
@@ -90,47 +115,52 @@ END
print qq!</TR>\n! ;
}
}
- print qq!</TABLE></CENTER>! ;
-
- print "<HR>";
+ print qq!</TABLE><BR><BR>!;
}
print <<END;
-<CENTER><FONT SIZE="+2">New packages</FONT></CENTER>
-These are packages the customer can purchase. Specify the quantity to add
-of each package.<BR><BR>
+Order new packages<BR><BR>
END
-my($cust_main)=qsearchs('cust_main',{'custnum'=>$custnum});
-my($agent)=qsearchs('agent',{'agentnum'=> $cust_main->agentnum });
+$cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
+$agent = qsearchs('agent',{'agentnum'=> $cust_main->agentnum });
-my($type_pkgs);
-my ($count) = 0 ;
-print qq!<CENTER><TABLE>! ;
+$count = 0;
+$pkgparts = 0;
+print qq!<TABLE>!;
foreach $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) {
+ $pkgparts++;
my($pkgpart)=$type_pkgs->pkgpart;
- print qq!<TR>! if ($count == 0) ;
+ print qq!<TR>! if ( $count == 0 );
+ my $value = $cgi->param("pkg$pkgpart") || 0;
print <<END;
<TD>
- <INPUT TYPE="text" NAME="pkg$pkgpart" VALUE="0" SIZE="2" MAXLENGTH="2">
+ <INPUT TYPE="text" NAME="pkg$pkgpart" VALUE="$value" SIZE="2" MAXLENGTH="2">
$pkgpart: $pkg{$pkgpart} - $comment{$pkgpart}</TD>\n
END
$count ++ ;
- if ($count == 2)
- {
+ if ( $count == 2 ) {
print qq!</TR>\n! ;
- $count = 0 ;
+ $count = 0;
}
}
-print qq!</TABLE></CENTER>! ;
+print qq!</TABLE>!;
-#otaker
-print qq!<INPUT TYPE="hidden" NAME="new_otaker" VALUE="$otaker">\n!;
+unless ( $pkgparts ) {
+ my $p2 = popurl(2);
+ my $typenum = $agent->typenum;
+ my $agent_type = qsearchs( 'agent_type', { 'typenum' => $typenum } );
+ my $atype = $agent_type->atype;
+ print <<END;
+(No <a href="${p2}browse/part_pkg.cgi">package definitions</a>, or agent type
+<a href="${p2}edit/agent_type.cgi?$typenum">$atype</a> not allowed to purchase
+any packages.)
+END
+}
#submit
-print qq!<P><CENTER><INPUT TYPE="submit" VALUE="Order"></CENTER>\n!;
-
print <<END;
+<P><INPUT TYPE="submit" VALUE="Order">
</FORM>
</BODY>
</HTML>
diff --git a/htdocs/edit/part_pkg.cgi b/htdocs/edit/part_pkg.cgi
index 9fe739bb7..f7ade88c8 100755
--- a/htdocs/edit/part_pkg.cgi
+++ b/htdocs/edit/part_pkg.cgi
@@ -1,5 +1,7 @@
#!/usr/bin/perl -Tw
#
+# $Id: part_pkg.cgi,v 1.9 1999-02-07 09:59:19 ivan Exp $
+#
# part_pkg.cgi: Add/Edit package (output form)
#
# ivan@sisd.com 97-dec-10
@@ -9,37 +11,99 @@
# bmccane@maxbaud.net 98-apr-3
#
# use FS::CGI, added inline documentation ivan@sisd.com 98-jul-12
+#
+# $Log: part_pkg.cgi,v $
+# Revision 1.9 1999-02-07 09:59:19 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.8 1999/01/19 05:13:39 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.7 1999/01/18 09:41:29 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.6 1998/12/17 06:17:05 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.5 1998/11/21 07:12:26 ivan
+# *** empty log message ***
+#
+# Revision 1.4 1998/11/21 07:11:08 ivan
+# *** empty log message ***
+#
+# Revision 1.3 1998/11/21 07:07:40 ivan
+# popurl, bugfix
+#
+# Revision 1.2 1998/11/15 13:14:55 ivan
+# first pass as per-user custom pricing
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $part_pkg $action $query $hashref $part_svc $count );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
+use FS::Record qw(qsearch qsearchs fields);
use FS::part_pkg;
+use FS::part_svc;
use FS::pkg_svc;
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl);
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
+if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {
+ $cgi->param('clone', $1);
+} else {
+ $cgi->param('clone', '');
+}
+if ( $cgi->param('pkgnum') && $cgi->param('pkgnum') =~ /^(\d+)$/ ) {
+ $cgi->param('pkgnum', $1);
+} else {
+ $cgi->param('pkgnum', '');
+}
-my($part_pkg,$action);
-if ( $cgi->var('QUERY_STRING') =~ /^(\d+)$/ ) { #editing
- $part_pkg=qsearchs('part_pkg',{'pkgpart'=>$1});
- $action='Edit';
-} else { #adding
- $part_pkg=create FS::part_pkg {};
- $action='Add';
+($query) = $cgi->keywords;
+$action = '';
+$part_pkg = '';
+if ( $cgi->param('error') ) {
+ $part_pkg = new FS::part_pkg ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_pkg')
+ } );
}
-my($hashref)=$part_pkg->hashref;
+if ( $cgi->param('clone') ) {
+ $action='Custom Pricing';
+ my $old_part_pkg =
+ qsearchs('part_pkg', { 'pkgpart' => $cgi->param('clone') } );
+ $part_pkg ||= $old_part_pkg->clone;
+} elsif ( $query && $query =~ /^(\d+)$/ ) {
+ $part_pkg ||= qsearchs('part_pkg',{'pkgpart'=>$1});
+} else {
+ $part_pkg ||= new FS::part_pkg {};
+}
+$action ||= $part_pkg->pkgpart ? 'Edit' : 'Add';
+$hashref = $part_pkg->hashref;
+
+print $cgi->header( '-expires' => 'now' ), header("$action Package Definition", menubar(
+ 'Main Menu' => popurl(2),
+ 'View all packages' => popurl(2). 'browse/part_pkg.cgi',
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-print header("$action Package Definition", menubar(
- 'Main Menu' => '../',
- 'View all packages' => '../browse/part_pkg.cgi',
-)), '<FORM ACTION="process/part_pkg.cgi" METHOD=POST>';
+print '<FORM ACTION="', popurl(1), 'process/part_pkg.cgi" METHOD=POST>';
+
+if ( $cgi->param('clone') ) {
+ print qq!<INPUT TYPE="hidden" NAME="clone" VALUE="!, $cgi->param('clone'), qq!">!;
+}
+if ( $cgi->param('pkgnum') ) {
+ print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="!, $cgi->param('pkgnum'), qq!">!;
+}
print qq!<INPUT TYPE="hidden" NAME="pkgpart" VALUE="$hashref->{pkgpart}">!,
"Package Part #", $hashref->{pkgpart} ? $hashref->{pkgpart} : "(NEW)";
@@ -54,41 +118,51 @@ Frequency (months) of recurring fee <INPUT TYPE="text" NAME="freq" VALUE="$hashr
</PRE>
+END
+
+unless ( $cgi->param('clone') ) {
+ print <<END;
Enter the quantity of each service this package includes.<BR><BR>
<TABLE BORDER><TR><TH><FONT SIZE=-1>Quan.</FONT></TH><TH>Service</TH>
<TH><FONT SIZE=-1>Quan.</FONT></TH><TH>Service</TH></TR>
END
+}
-my($part_svc);
-my($count) = 0 ;
-foreach $part_svc ( qsearch('part_svc',{}) ) {
-
- my($svcpart)=$part_svc->getfield('svcpart');
- my($pkg_svc)=qsearchs('pkg_svc',{
- 'pkgpart' => $part_pkg->getfield('pkgpart'),
+$count = 0;
+foreach $part_svc ( ( qsearch( 'part_svc', {} ) ) ) {
+ my $svcpart = $part_svc->svcpart;
+ my $pkg_svc = qsearchs( 'pkg_svc', {
+ 'pkgpart' => $cgi->param('clone') || $part_pkg->pkgpart,
'svcpart' => $svcpart,
- }) || create FS::pkg_svc({
- 'pkgpart' => $part_pkg->getfield('pkgpart'),
+ } ) || new FS::pkg_svc ( {
+ 'pkgpart' => $cgi->param('clone') || $part_pkg->pkgpart,
'svcpart' => $svcpart,
'quantity' => 0,
});
- next unless $pkg_svc;
-
- print qq!<TR>! if $count == 0 ;
- print qq!<TD><INPUT TYPE="text" NAME="pkg_svc$svcpart" SIZE=3 VALUE="!,
- $pkg_svc->getfield('quantity') || 0,qq!"></TD>!,
- qq!<TD><A HREF="part_svc.cgi?!,$part_svc->getfield('svcpart'),
- qq!">!, $part_svc->getfield('svc'), "</A></TD>";
- $count ++ ;
- if ($count == 2)
- {
- print qq!</TR>! ;
- $count = 0 ;
+ #? #next unless $pkg_svc;
+
+ unless ( defined ($cgi->param('clone')) && $cgi->param('clone') ) {
+ print '<TR>' if $count == 0 ;
+ print qq!<TD><INPUT TYPE="text" NAME="pkg_svc$svcpart" SIZE=3 VALUE="!,
+ $cgi->param("pkg_svc$svcpart") || $pkg_svc->quantity || 0,
+ qq!"></TD><TD><A HREF="part_svc.cgi?!,$part_svc->svcpart,
+ qq!">!, $part_svc->getfield('svc'), "</A></TD>";
+ $count++;
+ if ($count == 2)
+ {
+ print '</TR>';
+ $count = 0;
+ }
+ } else {
+ print qq!<INPUT TYPE="hidden" NAME="pkg_svc$svcpart" VALUE="!,
+ $cgi->param("pkg_svc$svcpart") || $pkg_svc->quantity || 0, qq!">\n!;
}
}
-print qq!</TR>! if ($count != 0) ;
-print "</TABLE>";
+unless ( $cgi->param('clone') ) {
+ print qq!</TR>! if ($count != 0) ;
+ print "</TABLE>";
+}
print qq!<BR><INPUT TYPE="submit" VALUE="!,
$hashref->{pkgpart} ? "Apply changes" : "Add package",
diff --git a/htdocs/edit/part_referral.cgi b/htdocs/edit/part_referral.cgi
index f29802239..24ac9dd82 100755
--- a/htdocs/edit/part_referral.cgi
+++ b/htdocs/edit/part_referral.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# agent.cgi: Add/Edit referral (output form)
+# $Id: part_referral.cgi,v 1.6 1999-04-07 11:43:23 ivan Exp $
#
# ivan@sisd.com 98-feb-23
#
@@ -10,40 +10,64 @@
# confisuing typo on submit button ivan@sisd.com 98-jun-14
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: part_referral.cgi,v $
+# Revision 1.6 1999-04-07 11:43:23 ivan
+# pick up errors right away, leave input
+#
+# Revision 1.5 1999/02/07 09:59:20 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.4 1999/01/19 05:13:41 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1999/01/18 09:41:30 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.2 1998/12/17 06:17:06 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $part_referral $action $hashref $p1 $query );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
+use FS::Record qw(qsearch qsearchs fields);
use FS::part_referral;
-use FS::CGI qw(header menubar);
+use FS::CGI qw(header menubar popurl);
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-
-my($part_referral,$action);
-if ( $cgi->var('QUERY_STRING') =~ /^(\d+)$/ ) { #editing
- $part_referral=qsearchs('part_referral',{'refnum'=>$1});
- $action='Edit';
+if ( $cgi->param('error') ) {
+ $part_referral = new FS::part_referral ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_referral')
+ } );
+} elsif ( $cgi->keywords ) {
+ my($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
+ $part_referral = qsearchs( 'part_referral', { 'refnum' => $1 } );
} else { #adding
- $part_referral=create FS::part_referral {};
- $action='Add';
+ $part_referral = new FS::part_referral {};
}
-my($hashref)=$part_referral->hashref;
+$action = $part_referral->refnum ? 'Edit' : 'Add';
+$hashref = $part_referral->hashref;
-print header("$action Referral", menubar(
- 'Main Menu' => '../',
- 'View all referrals' => "../browse/part_referral.cgi",
-)), <<END;
- <FORM ACTION="process/part_referral.cgi" METHOD=POST>
-END
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("$action Referral", menubar(
+ 'Main Menu' => popurl(2),
+ 'View all referrals' => popurl(2). "browse/part_referral.cgi",
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-#display
+print qq!<FORM ACTION="${p1}process/part_referral.cgi" METHOD=POST>!;
print qq!<INPUT TYPE="hidden" NAME="refnum" VALUE="$hashref->{refnum}">!,
"Referral #", $hashref->{refnum} ? $hashref->{refnum} : "(NEW)";
diff --git a/htdocs/edit/part_svc.cgi b/htdocs/edit/part_svc.cgi
index 491c013fe..e1f1e2ad5 100755
--- a/htdocs/edit/part_svc.cgi
+++ b/htdocs/edit/part_svc.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# part_svc.cgi: Add/Edit service (output form)
+# $Id: part_svc.cgi,v 1.12 1999-04-09 04:22:34 ivan Exp $
#
# ivan@sisd.com 97-nov-14
#
@@ -8,38 +8,80 @@
# bmccane@maxbaud.net 98-apr-3
#
# use FS::CGI, added inline documentation ivan@sisd.com 98-jul-12
+#
+# $Log: part_svc.cgi,v $
+# Revision 1.12 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.11 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.10 1999/04/08 13:01:50 ivan
+# [ AND DOCUMENT! ] all svc_acct services should have a default
+# or fixed shell
+#
+# Revision 1.9 1999/02/23 08:09:21 ivan
+# beginnings of one-screen new customer entry and some other miscellania
+#
+# Revision 1.8 1999/02/07 09:59:21 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.7 1999/01/19 05:13:42 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 09:41:31 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.5 1998/12/30 23:03:21 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.4 1998/12/17 06:17:07 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.3 1998/11/21 06:43:26 ivan
+# visual
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $part_svc $action $query $hashref $p %defs $svcdb );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs);
-use FS::part_svc qw(fields);
-use FS::CGI qw(header menubar);
+use FS::Record qw(qsearchs fields);
+use FS::part_svc;
+use FS::CGI qw(header menubar popurl table);
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-
-my($part_svc,$action);
-if ( $cgi->var('QUERY_STRING') =~ /^(\d+)$/ ) { #editing
+if ( $cgi->param('error') ) {
+ $part_svc = new FS::part_svc ( {
+ map { $_, scalar($cgi->param($_)) } fields('part_svc')
+ } );
+} elsif ( $cgi->keywords ) {
+ my ($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/;
$part_svc=qsearchs('part_svc',{'svcpart'=>$1});
- $action='Edit';
} else { #adding
- $part_svc=create FS::part_svc {};
- $action='Add';
+ $part_svc = new FS::part_svc {};
}
-my($hashref)=$part_svc->hashref;
+$action = $part_svc->svcpart ? 'Edit' : 'Add';
+$hashref = $part_svc->hashref;
-print header("$action Service Definition", menubar(
- 'Main Menu' => '../',
- 'View all services' => '../browse/part_svc.cgi',
-)), '<FORM ACTION="process/part_svc.cgi" METHOD=POST>';
+$p = popurl(2);
+print $cgi->header( '-expires' => 'now' ), header("$action Service Definition", menubar(
+ 'Main Menu' => $p,
+ 'View all services' => "${p}browse/part_svc.cgi",
+));
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+print '<FORM ACTION="', popurl(1), 'process/part_svc.cgi" METHOD=POST>';
print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$hashref->{svcpart}">!,
"Service Part #", $hashref->{svcpart} ? $hashref->{svcpart} : "(NEW)";
@@ -47,45 +89,48 @@ print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$hashref->{svcpart}">!,
print <<END;
<PRE>
Service <INPUT TYPE="text" NAME="svc" VALUE="$hashref->{svc}">
-Table <SELECT NAME="svcdb" SIZE=1>
-END
-
-print map '<OPTION'. ' SELECTED'x($_ eq $hashref->{svcdb}). ">$_\n", qw(
- svc_acct svc_domain svc_acct_sm svc_charge svc_wo
-);
-
-print <<END;
-</SELECT></PRE>
+</PRE>
Services are items you offer to your customers.
<UL><LI>svc_acct - Shell accounts, POP mailboxes, SLIP/PPP and ISDN accounts
<LI>svc_domain - Virtual domains
<LI>svc_acct_sm - Virtual domain mail aliasing
- <LI>svc_charge - One-time charges (Partially unimplemented)
- <LI>svc_wo - Work orders (Partially unimplemented)
+END
+# <LI>svc_charge - One-time charges (Partially unimplemented)
+# <LI>svc_wo - Work orders (Partially unimplemented)
+print <<END;
</UL>
-For the columns in the table selected above, you can set default or fixed
+For the selected table, you can give fields default or fixed (unchangable)
values. For example, a SLIP/PPP account may have a default (or perhaps fixed)
<B>slipip</B> of <B>0.0.0.0</B>, while a POP mailbox will probably have a fixed
blank <B>slipip</B> as well as a fixed shell something like <B>/bin/true</B> or
<B>/usr/bin/passwd</B>.
<BR><BR>
-<TABLE BORDER CELLPADDING=4><TR><TH>Table</TH><TH>Field</TH>
+END
+print &table(), '<TR><TH>Table<SELECT NAME="svcdb" SIZE=1>',
+ map '<OPTION'. ' SELECTED'x($_ eq $hashref->{svcdb}). ">$_\n", qw(
+ svc_acct svc_domain svc_acct_sm
+ );
+ print "</SELECT>";
+# svc_acct svc_domain svc_acct_sm svc_charge svc_wo
+
+print <<END;
+</TH><TH>Field</TH>
<TH COLSPAN=2>Modifier</TH></TR>
END
#these might belong somewhere else for other user interfaces
#pry need to eventually create stuff that's shared amount UIs
-my(%defs)=(
+%defs = (
'svc_acct' => {
'dir' => 'Home directory',
'uid' => 'UID (set to fixed and blank for dial-only)',
'slipip' => 'IP address',
- 'popnum' => '<A HREF="../browse/svc_acct_pop.cgi/">POP number</A>',
+ 'popnum' => qq!<A HREF="$p/browse/svc_acct_pop.cgi/">POP number</A>!,
'username' => 'Username',
'quota' => '(unimplemented)',
'_password' => 'Password',
'gid' => 'GID (when blank, defaults to UID)',
- 'shell' => 'Shell',
+ 'shell' => 'Shell (all service definitions should have a default or fixed shell that is present in the <b>shells</b> configuration file)',
'finger' => 'GECOS',
},
'svc_domain' => {
@@ -105,9 +150,9 @@ my(%defs)=(
},
);
-my($svcdb);
+# svc_acct svc_domain svc_acct_sm svc_charge svc_wo
foreach $svcdb ( qw(
- svc_acct svc_domain svc_acct_sm svc_charge svc_wo
+ svc_acct svc_domain svc_acct_sm
) ) {
my(@rows)=map { /^${svcdb}__(.*)$/; $1 }
@@ -119,25 +164,28 @@ foreach $svcdb ( qw(
my($ptmp)="<TD ROWSPAN=$rowspan>$svcdb</TD>";
my($row);
foreach $row (@rows) {
- my($value)=$part_svc->getfield($svcdb.'__'.$row);
- my($flag)=$part_svc->getfield($svcdb.'__'.$row.'_flag');
- print "<TR>$ptmp<TD>$row - <FONT SIZE=-1>$defs{$svcdb}{$row}</FONT></TD>";
+ my $value = $part_svc->getfield($svcdb. '__'. $row);
+ my $flag = $part_svc->getfield($svcdb. '__'. $row. '_flag');
+ print "<TR>$ptmp<TD>$row";
+ print "- <FONT SIZE=-1>$defs{$svcdb}{$row}</FONT>"
+ if defined $defs{$svcdb}{$row};
+ print "</TD>";
print qq!<TD><INPUT TYPE="radio" NAME="${svcdb}__${row}_flag" VALUE=""!.
- ' CHECKED'x($flag eq ''). "><BR>Off</TD>";
+ ' CHECKED'x($flag eq ''). ">Off</TD>";
print qq!<TD><INPUT TYPE="radio" NAME="${svcdb}__${row}_flag" VALUE="D"!.
' CHECKED'x($flag eq 'D'). ">Default ";
print qq!<INPUT TYPE="radio" NAME="${svcdb}__${row}_flag" VALUE="F"!.
' CHECKED'x($flag eq 'F'). ">Fixed ";
- print qq!<BR><INPUT TYPE="text" NAME="${svcdb}__${row}" VALUE="$value">!,
- "</TD></TR>";
+ print qq!<INPUT TYPE="text" NAME="${svcdb}__${row}" VALUE="$value">!,
+ "</TD></TR>\n";
$ptmp='';
}
}
print "</TABLE>";
-print qq!\n<CENTER><BR><INPUT TYPE="submit" VALUE="!,
+print qq!\n<BR><INPUT TYPE="submit" VALUE="!,
$hashref->{svcpart} ? "Apply changes" : "Add service",
- qq!"></CENTER>!;
+ qq!">!;
print <<END;
diff --git a/htdocs/edit/process/agent.cgi b/htdocs/edit/process/agent.cgi
index 5d1ce3232..c1b397aac 100755
--- a/htdocs/edit/process/agent.cgi
+++ b/htdocs/edit/process/agent.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/agent.cgi: Edit agent (process form)
+# $Id: agent.cgi,v 1.7 1999-01-25 12:09:57 ivan Exp $
#
# ivan@sisd.com 97-dec-12
#
@@ -8,34 +8,51 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: agent.cgi,v $
+# Revision 1.7 1999-01-25 12:09:57 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.6 1999/01/19 05:13:47 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 22:47:49 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.4 1998/12/30 23:03:26 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.3 1998/12/17 08:40:16 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
+# Revision 1.2 1998/11/23 07:52:29 ivan
+# *** empty log message ***
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi $agentnum $old $new $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
-use FS::agent qw(fields);
-use FS::CGI qw(idiot);
-
-my($req)=new CGI::Request; # create form object
+use FS::Record qw(qsearch qsearchs fields);
+use FS::agent;
+use FS::CGI qw(popurl);
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
-my($agentnum)=$req->param('agentnum');
+&cgisuidsetup($cgi);
-my($old)=qsearchs('agent',{'agentnum'=>$agentnum}) if $agentnum;
+$agentnum = $cgi->param('agentnum');
-#unmunge typenum
-$req->param('typenum') =~ /^(\d+)(:.*)?$/;
-$req->param('typenum',$1);
+$old = qsearchs('agent',{'agentnum'=>$agentnum}) if $agentnum;
-my($new)=create FS::agent ( {
+$new = new FS::agent ( {
map {
- $_, $req->param($_);
+ $_, scalar($cgi->param($_));
} fields('agent')
} );
-my($error);
if ( $agentnum ) {
$error=$new->replace($old);
} else {
@@ -44,10 +61,9 @@ if ( $agentnum ) {
}
if ( $error ) {
- &idiot($error);
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "agent.cgi?". $cgi->query_string );
} else {
- #$req->cgi->redirect("../../view/agent.cgi?$agentnum");
- #$req->cgi->redirect("../../edit/agent.cgi?$agentnum");
- $req->cgi->redirect("../../browse/agent.cgi");
+ print $cgi->redirect(popurl(3). "browse/agent.cgi");
}
diff --git a/htdocs/edit/process/agent_type.cgi b/htdocs/edit/process/agent_type.cgi
index 43f129fd5..99c54ab3b 100755
--- a/htdocs/edit/process/agent_type.cgi
+++ b/htdocs/edit/process/agent_type.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/agent_type.cgi: Edit agent type (process form)
+# $Id: agent_type.cgi,v 1.7 1999-01-25 12:09:58 ivan Exp $
#
# ivan@sisd.com 97-dec-11
#
@@ -8,29 +8,51 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: agent_type.cgi,v $
+# Revision 1.7 1999-01-25 12:09:58 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.6 1999/01/19 05:13:48 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 22:47:50 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.4 1998/12/30 23:03:27 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.3 1998/12/17 08:40:17 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
+# Revision 1.2 1998/11/21 07:49:20 ivan
+# s/CGI::Request/CGI.pm/
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi $typenum $old $new $error $part_pkg );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
+use FS::CGI qw( popurl);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
-use FS::agent_type qw(fields);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::agent_type;
use FS::type_pkgs;
-use FS::CGI qw(idiot);
+use FS::part_pkg;
-my($req)=new CGI::Request;
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-my($typenum)=$req->param('typenum');
-my($old)=qsearchs('agent_type',{'typenum'=>$typenum}) if $typenum;
+$typenum = $cgi->param('typenum');
+$old = qsearchs('agent_type',{'typenum'=>$typenum}) if $typenum;
-my($new)=create FS::agent_type ( {
+$new = new FS::agent_type ( {
map {
- $_, $req->param($_);
+ $_, scalar($cgi->param($_));
} fields('agent_type')
} );
-my($error);
if ( $typenum ) {
$error=$new->replace($old);
} else {
@@ -39,11 +61,11 @@ if ( $typenum ) {
}
if ( $error ) {
- idiot($error);
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "agent_type.cgi?". $cgi->query_string );
exit;
}
-my($part_pkg);
foreach $part_pkg (qsearch('part_pkg',{})) {
my($pkgpart)=$part_pkg->getfield('pkgpart');
@@ -51,33 +73,24 @@ foreach $part_pkg (qsearch('part_pkg',{})) {
'typenum' => $typenum,
'pkgpart' => $pkgpart,
});
- if ( $type_pkgs && ! $req->param("pkgpart$pkgpart") ) {
+ if ( $type_pkgs && ! $cgi->param("pkgpart$pkgpart") ) {
my($d_type_pkgs)=$type_pkgs; #need to save $type_pkgs for below.
- $error=$d_type_pkgs->del; #FS::Record not FS::type_pkgs,
- #so ->del not ->delete. hmm. hmm.
- if ( $error ) {
- idiot($error);
- exit;
- }
+ $error=$d_type_pkgs->delete;
+ die $error if $error;
- } elsif ( $req->param("pkgpart$pkgpart")
+ } elsif ( $cgi->param("pkgpart$pkgpart")
&& ! $type_pkgs
) {
#ok to clobber it now (but bad form nonetheless?)
- $type_pkgs=create FS::type_pkgs ({
+ $type_pkgs=new FS::type_pkgs ({
'typenum' => $typenum,
'pkgpart' => $pkgpart,
});
$error= $type_pkgs->insert;
- if ( $error ) {
- idiot($error);
- exit;
- }
+ die $error if $error;
}
}
-#$req->cgi->redirect("../../view/agent_type.cgi?$typenum");
-#$req->cgi->redirect("../../edit/agent_type.cgi?$typenum");
-$req->cgi->redirect("../../browse/agent_type.cgi");
+print $cgi->redirect(popurl(3). "browse/agent_type.cgi");
diff --git a/htdocs/edit/process/cust_credit.cgi b/htdocs/edit/process/cust_credit.cgi
index e660b4c78..ea9c5a3a2 100755
--- a/htdocs/edit/process/cust_credit.cgi
+++ b/htdocs/edit/process/cust_credit.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# process/cust_credit.cgi: Add a credit (process form)
+# $Id: cust_credit.cgi,v 1.7 1999-04-07 15:23:05 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/cust_credit.cgi
#
-# Note: Should be run setuid root as user nobody.
-#
# ivan@voicenet.com 96-dec-05 -> 96-dec-08
#
# post a refund if $new_paybatch
@@ -20,51 +18,59 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: cust_credit.cgi,v $
+# Revision 1.7 1999-04-07 15:23:05 ivan
+# don't use anchor in redirect
+#
+# Revision 1.6 1999/02/28 00:03:41 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/01/25 12:09:59 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.4 1999/01/19 05:13:49 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1999/01/18 22:47:51 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.2 1998/12/17 08:40:18 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $custnum $new $error );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup getotaker);
+use FS::CGI qw(popurl);
+use FS::Record qw(fields);
use FS::cust_credit;
-my($req)=new CGI::Request; # create form object
-cgisuidsetup($req->cgi);
+$cgi = new CGI;
+cgisuidsetup($cgi);
-$req->param('custnum') =~ /^(\d*)$/ or die "Illegal custnum!";
-my($custnum)=$1;
+$cgi->param('custnum') =~ /^(\d*)$/ or die "Illegal custnum!";
+$custnum = $1;
-$req->param('otaker',getotaker);
+$cgi->param('otaker',getotaker);
-my($new) = create FS::cust_credit ( {
+$new = new FS::cust_credit ( {
map {
- $_, $req->param($_);
- } qw(custnum _date amount otaker reason)
+ $_, scalar($cgi->param($_));
+ #} qw(custnum _date amount otaker reason)
+ } fields('cust_credit')
} );
-my($error);
$error=$new->insert;
-&idiot($error) if $error;
-
-#no errors, no refund, so view our credit.
-$req->cgi->redirect("../../view/cust_main.cgi?$custnum#history");
-
-sub idiot {
- my($error)=@_;
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error posting credit/refund</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error posting credit/refund</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and press the <I>Post</I> button again.
- </BODY>
-</HTML>
-END
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_credit.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum");
}
+
diff --git a/htdocs/edit/process/cust_main.cgi b/htdocs/edit/process/cust_main.cgi
index 7664dfcb8..25dc0299b 100755
--- a/htdocs/edit/process/cust_main.cgi
+++ b/htdocs/edit/process/cust_main.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# process/cust_main.cgi: Edit a customer (process form)
+# $Id: cust_main.cgi,v 1.11 1999-08-10 12:54:06 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/cust_main.cgi
#
-# Note: Should be run setuid root as user nobody.
-#
# ivan@voicenet.com 96-dec-04
#
# added referral check
@@ -20,83 +18,175 @@
# Changes to allow page to work at a relative position in server
# Changed 'day' to 'daytime' because Pg6.3 reserves the day word
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: cust_main.cgi,v $
+# Revision 1.11 1999-08-10 12:54:06 ivan
+# use FS::cust_pkg::pkgpart_href
+#
+# Revision 1.10 1999/04/14 07:47:53 ivan
+# i18n fixes
+#
+# Revision 1.9 1999/04/07 15:22:19 ivan
+# don't use anchor in redirect
+#
+# Revision 1.8 1999/03/25 13:55:10 ivan
+# one-screen new customer entry (including package and service) for simple
+# packages with one svc_acct service
+#
+# Revision 1.7 1999/02/28 00:03:42 ivan
+# removed misleading comments
+#
+# Revision 1.6 1999/01/25 12:10:00 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:50 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:22:32 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.3 1998/12/17 08:40:19 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
+# Revision 1.2 1998/11/18 08:57:36 ivan
+# i18n, s/CGI-modules/CGI.pm/, FS::CGI::idiot instead of inline, FS::CGI::popurl
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $payby @invoicing_list $new $custnum $error );
+use vars qw( $cust_pkg $cust_svc $svc_acct );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
-use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs);
+use FS::UID qw(cgisuidsetup getotaker);
+use FS::CGI qw( popurl );
+use FS::Record qw( qsearch qsearchs fields );
use FS::cust_main;
+use FS::type_pkgs;
+use FS::agent;
-my($req)=new CGI::Request; # create form object
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-&cgisuidsetup($req->cgi);
+#unmunge stuff
-#create new record object
+$cgi->param('tax','') unless defined($cgi->param('tax'));
+
+$cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] );
+
+$cgi->param('state') =~ /^(\w*)( \(([\w ]+)\))? ?\/ ?(\w+)$/
+ or die "Oops, illegal \"state\" param: ". $cgi->param('state');
+$cgi->param('state', $1);
+$cgi->param('county', $3 || '');
+$cgi->param('country', $4);
-#unmunge agentnum
-$req->param('agentnum',
- (split(/:/, ($req->param('agentnum'))[0] ))[0]
-);
+if ( $payby = $cgi->param('payby') ) {
+ $cgi->param('payinfo', $cgi->param( $payby. '_payinfo' ) );
+ $cgi->param('paydate',
+ $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' ) );
+ $cgi->param('payname', $cgi->param( $payby. '_payname' ) );
+}
-#unmunge tax
-$req->param('tax','') unless defined($req->param('tax'));
+$cgi->param('otaker', &getotaker );
-#unmunge refnum
-$req->param('refnum',
- (split(/:/, ($req->param('refnum'))[0] ))[0]
-);
+@invoicing_list = split( /\s*\,\s*/, $cgi->param('invoicing_list') );
+push @invoicing_list, 'POST' if $cgi->param('invoicing_list_POST');
-#unmunge state/county
-$req->param('state') =~ /^(\w+)( \((\w+)\))?$/;
-$req->param('state', $1);
-$req->param('county', $3 || '');
+#create new record object
-my($new) = create FS::cust_main ( {
+$new = new FS::cust_main ( {
map {
- $_, $req->param("$_") || ''
- } qw(custnum agentnum last first ss company address1 address2 city county
- state zip country daytime night fax payby payinfo paydate payname tax
- otaker refnum)
+ $_, scalar($cgi->param($_))
+# } qw(custnum agentnum last first ss company address1 address2 city county
+# state zip daytime night fax payby payinfo paydate payname tax
+# otaker refnum)
+ } fields('cust_main')
} );
-if ( $new->custnum eq '' ) {
+#perhaps the invocing_list magic should move to cust_main.pm?
+$error = $new->check_invoicing_list( \@invoicing_list );
- my($error)=$new->insert;
- &idiot($error) if $error;
+#perhaps this stuff should go to cust_main.pm as well
+$cust_pkg = '';
+$svc_acct = '';
+if ( $new->custnum eq '' ) {
+ if ( $cgi->param('pkgpart_svcpart') ) {
+ my $x = $cgi->param('pkgpart_svcpart');
+ $x =~ /^(\d+)_(\d+)$/;
+ my($pkgpart, $svcpart) = ($1, $2);
+ #false laziness: copied from FS::cust_pkg::order (which should become a
+ #FS::cust_main method)
+ my(%part_pkg);
+ # generate %part_pkg
+ # $part_pkg{$pkgpart} is true iff $custnum may purchase $pkgpart
+ my $agent = qsearchs('agent',{'agentnum'=> $new->agentnum });
+ #my($type_pkgs);
+ #foreach $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) {
+ # my($pkgpart)=$type_pkgs->pkgpart;
+ # $part_pkg{$pkgpart}++;
+ #}
+ # $pkgpart_href->{PKGPART} is true iff $custnum may purchase $pkgpart
+ my $pkgpart_href = $agent->pkgpart_hashref;
+ #eslaf
+
+ # this should wind up in FS::cust_pkg!
+ $error ||= "Agent ". $new->agentnum. " (type ". $agent->typenum. ") can't".
+ "purchase pkgpart ". $pkgpart
+ #unless $part_pkg{ $pkgpart };
+ unless $pkgpart_href->{ $pkgpart };
+
+ $cust_pkg = new FS::cust_pkg ( {
+ #later 'custnum' => $custnum,
+ 'pkgpart' => $pkgpart,
+ } );
+ $error ||= $cust_pkg->check;
+
+ #$cust_svc = new FS::cust_svc ( { 'svcpart' => $svcpart } );
+
+ #$error ||= $cust_svc->check;
+
+ $svc_acct = new FS::svc_acct ( {
+ 'svcpart' => $svcpart,
+ 'username' => $cgi->param('username'),
+ '_password' => $cgi->param('_password'),
+ 'popnum' => $cgi->param('popnum'),
+ } );
+
+ my $y = $svc_acct->setdefault; # arguably should be in new method
+ $error ||= $y unless ref($y);
+ #and just in case you were silly
+ $svc_acct->svcpart($svcpart);
+ $svc_acct->username($cgi->param('username'));
+ $svc_acct->_password($cgi->param('_password'));
+ $svc_acct->popnum($cgi->param('popnum'));
+
+ $error ||= $svc_acct->check;
+
+ } elsif ( $cgi->param('username') ) { #good thing to catch
+ $error = "Can't assign username without a package!";
+ }
+
+ $error ||= $new->insert;
+ if ( $cust_pkg && ! $error ) {
+ $cust_pkg->custnum( $new->custnum );
+ $error ||= $cust_pkg->insert;
+ warn "WARNING: $error on pre-checked cust_pkg record!" if $error;
+ $svc_acct->pkgnum( $cust_pkg->pkgnum );
+ $error ||= $svc_acct->insert;
+ warn "WARNING: $error on pre-checked svc_acct record!" if $error;
+ }
} else { #create old record object
-
- my($old) = qsearchs( 'cust_main', { 'custnum', $new->custnum } );
- &idiot("Old record not found!") unless $old;
- my($error)=$new->replace($old);
- &idiot($error) if $error;
-
-}
-
-my($custnum)=$new->custnum;
-$req->cgi->redirect("../../view/cust_main.cgi?$custnum#cust_main");
-
-sub idiot {
- my($error)=@_;
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error updating customer information</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error updating customer information</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and submit the form again.
- </BODY>
-</HTML>
-END
-
- exit;
-
+ my $old = qsearchs( 'cust_main', { 'custnum' => $new->custnum } );
+ $error ||= "Old record not found!" unless $old;
+ $error ||= $new->replace($old);
}
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_main.cgi?". $cgi->query_string );
+} else {
+ $new->invoicing_list( \@invoicing_list );
+ $custnum = $new->custnum;
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum");
+}
diff --git a/htdocs/edit/process/cust_main_county-expand.cgi b/htdocs/edit/process/cust_main_county-expand.cgi
index a821560c6..7e618c7b8 100755
--- a/htdocs/edit/process/cust_main_county-expand.cgi
+++ b/htdocs/edit/process/cust_main_county-expand.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/cust_main_county-expand.cgi: Expand counties (process form)
+# $Id: cust_main_county-expand.cgi,v 1.6 1999-01-25 12:19:07 ivan Exp $
#
# ivan@sisd.com 97-dec-16
#
@@ -12,45 +12,70 @@
# lose background, FS::CGI
# undo default tax to 0.0 if using Pg6.3: comes from pre-expanded record
# for that state
-#ivan@sisd.com 98-sep-2
+# ivan@sisd.com 98-sep-2
+#
+# $Log: cust_main_county-expand.cgi,v $
+# Revision 1.6 1999-01-25 12:19:07 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:51 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 22:47:52 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.3 1998/12/17 08:40:20 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
+# Revision 1.2 1998/11/18 09:01:40 ivan
+# i18n! i18n!
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi $taxnum $cust_main_county @expansion $expansion );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup datasrc);
use FS::Record qw(qsearch qsearchs);
+use FS::CGI qw(popurl);
use FS::cust_main_county;
-use FS::CGI qw(eidiot);
-
-my($req)=new CGI::Request; # create form object
+use FS::cust_main;
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-$req->param('taxnum') =~ /^(\d+)$/ or die "Illegal taxnum!";
-my($taxnum)=$1;
-my($cust_main_county)=qsearchs('cust_main_county',{'taxnum'=>$taxnum})
+$cgi->param('taxnum') =~ /^(\d+)$/ or die "Illegal taxnum!";
+$taxnum = $1;
+$cust_main_county = qsearchs('cust_main_county',{'taxnum'=>$taxnum})
or die ("Unknown taxnum!");
-my(@counties);
-if ( $req->param('delim') eq 'n' ) {
- @counties=split(/\n/,$req->param('counties'));
-} elsif ( $req->param('delim') eq 's' ) {
- @counties=split(/\s+/,$req->param('counties'));
+if ( $cgi->param('delim') eq 'n' ) {
+ @expansion=split(/\n/,$cgi->param('expansion'));
+} elsif ( $cgi->param('delim') eq 's' ) {
+ @expansion=split(/\s+/,$cgi->param('expansion'));
} else {
die "Illegal delim!";
}
-@counties=map {
- /^\s*([\w\- ]+)\s*$/ or eidiot("Illegal county");
+@expansion=map {
+ unless ( /^\s*([\w\- ]+)\s*$/ ) {
+ $cgi->param('error', "Illegal item in expansion");
+ print $cgi->redirect(popurl(2). "cust_main_county-expand.cgi?". $cgi->query_string );
+ exit;
+ }
$1;
-} @counties;
+} @expansion;
-my($county);
-foreach ( @counties) {
+foreach ( @expansion) {
my(%hash)=$cust_main_county->hash;
- my($new)=create FS::cust_main_county \%hash;
+ my($new)=new FS::cust_main_county \%hash;
$new->setfield('taxnum','');
- $new->setfield('county',$_);
+ if ( ! $cust_main_county->state ) {
+ $new->setfield('state',$_);
+ } else {
+ $new->setfield('county',$_);
+ }
#if (datasrc =~ m/Pg/)
#{
# $new->setfield('tax',0.0);
@@ -62,10 +87,11 @@ foreach ( @counties) {
unless ( qsearch('cust_main',{
'state' => $cust_main_county->getfield('state'),
'county' => $cust_main_county->getfield('county'),
+ 'country' => $cust_main_county->getfield('country'),
} ) ) {
my($error)=($cust_main_county->delete);
die $error if $error;
}
-$req->cgi->redirect("../../edit/cust_main_county.cgi");
+print $cgi->redirect(popurl(3). "edit/cust_main_county.cgi");
diff --git a/htdocs/edit/process/cust_main_county.cgi b/htdocs/edit/process/cust_main_county.cgi
index 58eaa63ce..0fc1708c5 100755
--- a/htdocs/edit/process/cust_main_county.cgi
+++ b/htdocs/edit/process/cust_main_county.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/agent.cgi: Edit cust_main_county (process form)
+# $Id: cust_main_county.cgi,v 1.6 1999-01-25 12:19:08 ivan Exp $
#
# ivan@sisd.com 97-dec-16
#
@@ -8,31 +8,53 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: cust_main_county.cgi,v $
+# Revision 1.6 1999-01-25 12:19:08 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:52 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 22:47:53 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.3 1998/12/17 08:40:21 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
+# Revision 1.2 1998/11/18 09:01:41 ivan
+# i18n! i18n!
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl);
use FS::Record qw(qsearch qsearchs);
use FS::cust_main_county;
-use FS::CGI qw(eidiot);
-
-my($req)=new CGI::Request; # create form object
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-foreach ( $req->params ) {
+foreach ( $cgi->param ) {
/^tax(\d+)$/ or die "Illegal form $_!";
my($taxnum)=$1;
my($old)=qsearchs('cust_main_county',{'taxnum'=>$taxnum})
or die "Couldn't find taxnum $taxnum!";
- next unless $old->getfield('tax') ne $req->param("tax$taxnum");
+ next unless $old->getfield('tax') ne $cgi->param("tax$taxnum");
my(%hash)=$old->hash;
- $hash{tax}=$req->param("tax$taxnum");
- my($new)=create FS::cust_main_county \%hash;
+ $hash{tax}=$cgi->param("tax$taxnum");
+ my($new)=new FS::cust_main_county \%hash;
my($error)=$new->replace($old);
- eidiot($error) if $error;
+ if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_main_county.cgi?". $cgi->query_string );
+ exit;
+ }
}
-$req->cgi->redirect("../../browse/cust_main_county.cgi");
+print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi");
diff --git a/htdocs/edit/process/cust_pay.cgi b/htdocs/edit/process/cust_pay.cgi
index 9ec97532b..ca5029c3c 100755
--- a/htdocs/edit/process/cust_pay.cgi
+++ b/htdocs/edit/process/cust_pay.cgi
@@ -1,57 +1,67 @@
#!/usr/bin/perl -Tw
#
-# process/cust_pay.cgi: Add a payment (process form)
+# $Id: cust_pay.cgi,v 1.7 1999-02-28 00:03:43 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/cust_pay.cgi
#
-# Note: Should be run setuid root as user nobody.
-#
# ivan@voicenet.com 96-dec-11
#
# rewrite ivan@sisd.com 98-mar-16
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: cust_pay.cgi,v $
+# Revision 1.7 1999-02-28 00:03:43 ivan
+# removed misleading comments
+#
+# Revision 1.6 1999/01/25 12:19:09 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.5 1999/01/19 05:13:53 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 22:47:54 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.3 1998/12/30 23:03:28 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.2 1998/12/17 08:40:22 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $invnum $new $error );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::cust_pay qw(fields);
+use FS::CGI qw(popurl);
+use FS::Record qw(fields);
+use FS::cust_pay;
-my($req)=new CGI::Request;
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-$req->param('invnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
-my($invnum)=$1;
+$cgi->param('invnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+$invnum = $1;
-my($new) = create FS::cust_pay ( {
+$new = new FS::cust_pay ( {
map {
- $_, $req->param($_);
- } qw(invnum paid _date payby payinfo paybatch)
+ $_, scalar($cgi->param($_));
+ #} qw(invnum paid _date payby payinfo paybatch)
+ } fields('cust_pay')
} );
-my($error);
$error=$new->insert;
-if ($error) { #error!
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error posting payment</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error posting payment</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and press the <I>Post</I> button again.
- </BODY>
-</HTML>
-END
-} else { #no errors!
- $req->cgi->redirect("../../view/cust_bill.cgi?$invnum");
+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");
}
diff --git a/htdocs/edit/process/cust_pkg.cgi b/htdocs/edit/process/cust_pkg.cgi
index 6f5bc875a..9d82b3c24 100755
--- a/htdocs/edit/process/cust_pkg.cgi
+++ b/htdocs/edit/process/cust_pkg.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/cust_pkg.cgi: Add/edit packages (process form)
+# $Id: cust_pkg.cgi,v 1.7 1999-04-07 15:24:06 ivan Exp $
#
# this is for changing packages around, not for editing things within the
# package
@@ -8,8 +8,6 @@
# Usage: post form to:
# http://server.name/path/cust_pkg.cgi
#
-# Note: Should be run setuid root as user nobody.
-#
# ivan@voicenet.com 97-mar-21 - 97-mar-24
#
# rewrote for new API
@@ -19,55 +17,64 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: cust_pkg.cgi,v $
+# Revision 1.7 1999-04-07 15:24:06 ivan
+# don't use anchor in redirect
+#
+# Revision 1.6 1999/02/28 00:03:44 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/02/07 09:59:26 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.3 1999/01/19 05:13:54 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.2 1998/12/17 08:40:23 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $custnum @remove_pkgnums @pkgparts $pkgpart $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl);
use FS::cust_pkg;
-my($req)=new CGI::Request; # create form object
-
-&cgisuidsetup($req->cgi);
+$cgi = new CGI; # create form object
+&cgisuidsetup($cgi);
+$error = '';
#untaint custnum
-$req->param('new_custnum') =~ /^(\d+)$/;
-my($custnum)=$1;
+$cgi->param('custnum') =~ /^(\d+)$/;
+$custnum = $1;
-my(@remove_pkgnums) = map {
+@remove_pkgnums = map {
/^(\d+)$/ or die "Illegal remove_pkg value!";
$1;
-} $req->param('remove_pkg');
+} $cgi->param('remove_pkg');
-my(@pkgparts);
-my($pkgpart);
-foreach $pkgpart ( map /^pkg(\d+)$/ ? $1 : (), $req->params ) {
- my($num_pkgs)=$req->param("pkg$pkgpart");
- while ( $num_pkgs-- ) {
- push @pkgparts,$pkgpart;
+foreach $pkgpart ( map /^pkg(\d+)$/ ? $1 : (), $cgi->param ) {
+ if ( $cgi->param("pkg$pkgpart") =~ /^(\d+)$/ ) {
+ my $num_pkgs = $1;
+ while ( $num_pkgs-- ) {
+ push @pkgparts,$pkgpart;
+ }
+ } else {
+ $error = "Illegal quantity";
+ last;
}
}
-my($error) = FS::cust_pkg::order($custnum,\@pkgparts,\@remove_pkgnums);
+$error ||= FS::cust_pkg::order($custnum,\@pkgparts,\@remove_pkgnums);
if ($error) {
- CGI::Base::SendHeaders();
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error updating packages</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error updating packages</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and submit the form again.
- </BODY>
-</HTML>
-END
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "cust_pkg.cgi?". $cgi->query_string );
} else {
- $req->cgi->redirect("../../view/cust_main.cgi?$custnum#cust_pkg");
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum");
}
diff --git a/htdocs/edit/process/part_pkg.cgi b/htdocs/edit/process/part_pkg.cgi
index 7d787819a..adf4672bd 100755
--- a/htdocs/edit/process/part_pkg.cgi
+++ b/htdocs/edit/process/part_pkg.cgi
@@ -1,5 +1,7 @@
#!/usr/bin/perl -Tw
#
+# $Id: part_pkg.cgi,v 1.8 1999-02-07 09:59:27 ivan Exp $
+#
# process/part_pkg.cgi: Edit package definitions (process form)
#
# ivan@sisd.com 97-dec-10
@@ -13,67 +15,117 @@
# Added `|| 0 ' when getting quantity off web page ivan@sisd.com 98-jun-4
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: part_pkg.cgi,v $
+# Revision 1.8 1999-02-07 09:59:27 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.7 1999/01/19 05:13:55 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 22:47:56 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.5 1998/12/30 23:03:29 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.4 1998/12/17 08:40:24 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
+# Revision 1.3 1998/11/21 07:17:58 ivan
+# bugfix to work for regular aswell as custom pricing
+#
+# Revision 1.2 1998/11/15 13:16:15 ivan
+# first pass as per-user custom pricing
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $pkgpart $old $new $part_svc $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
-use FS::part_pkg qw(fields);
+use FS::CGI qw(popurl);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::part_pkg;
use FS::pkg_svc;
-use FS::CGI qw(eidiot);
+use FS::cust_pkg;
-my($req)=new CGI::Request; # create form object
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-&cgisuidsetup($req->cgi);
+$pkgpart = $cgi->param('pkgpart');
-my($pkgpart)=$req->param('pkgpart');
+$old = qsearchs('part_pkg',{'pkgpart'=>$pkgpart}) if $pkgpart;
-my($old)=qsearchs('part_pkg',{'pkgpart'=>$pkgpart}) if $pkgpart;
-
-my($new)=create FS::part_pkg ( {
+$new = new FS::part_pkg ( {
map {
- $_, $req->param($_);
+ $_, scalar($cgi->param($_));
} fields('part_pkg')
} );
+#most of the stuff below should move to part_pkg.pm
+
+foreach $part_svc ( qsearch('part_svc', {} ) ) {
+ my $quantity = $cgi->param('pkg_svc'. $part_svc->svcpart) || 0;
+ unless ( $quantity =~ /^(\d+)$/ ) {
+ $cgi->param('error', "Illegal quantity" );
+ print $cgi->redirect(popurl(2). "part_pkg.cgi?". $cgi->query_string );
+ exit;
+ }
+}
+
+local $SIG{HUP} = 'IGNORE';
+local $SIG{INT} = 'IGNORE';
+local $SIG{QUIT} = 'IGNORE';
+local $SIG{TERM} = 'IGNORE';
+local $SIG{TSTP} = 'IGNORE';
+local $SIG{PIPE} = 'IGNORE';
+
if ( $pkgpart ) {
- my($error)=$new->replace($old);
- eidiot($error) if $error;
+ $error = $new->replace($old);
} else {
- my($error)=$new->insert;
- eidiot($error) if $error;
- $pkgpart=$new->getfield('pkgpart');
+ $error = $new->insert;
+ $pkgpart=$new->pkgpart;
+}
+if ( $error ) {
+ $cgi->param('error', $error );
+ print $cgi->redirect(popurl(2). "part_pkg.cgi?". $cgi->query_string );
+ exit;
}
-my($part_svc);
foreach $part_svc (qsearch('part_svc',{})) {
-# don't update non-changing records in part_svc (causing harmless but annoying
-# "Records identical" errors). ivan@sisd.com 98-jan-19
- #my($quantity)=$req->param('pkg_svc'. $part_svc->getfield('svcpart')),
- my($quantity)=$req->param('pkg_svc'. $part_svc->svcpart) || 0,
- my($old_pkg_svc)=qsearchs('pkg_svc',{
- 'pkgpart' => $pkgpart,
- 'svcpart' => $part_svc->getfield('svcpart'),
- });
- my($old_quantity)=$old_pkg_svc ? $old_pkg_svc->quantity : 0;
+ my $quantity = $cgi->param('pkg_svc'. $part_svc->svcpart) || 0;
+ my $old_pkg_svc = qsearchs('pkg_svc', {
+ 'pkgpart' => $pkgpart,
+ 'svcpart' => $part_svc->svcpart,
+ } );
+ my $old_quantity = $old_pkg_svc ? $old_pkg_svc->quantity : 0;
next unless $old_quantity != $quantity; #!here
- my($new_pkg_svc)=create FS::pkg_svc({
+ my $new_pkg_svc = new FS::pkg_svc( {
'pkgpart' => $pkgpart,
- 'svcpart' => $part_svc->getfield('svcpart'),
- #'quantity' => $req->param('pkg_svc'. $part_svc->getfield('svcpart')),
+ 'svcpart' => $part_svc->svcpart,
'quantity' => $quantity,
- });
- if ($old_pkg_svc) {
- my($error)=$new_pkg_svc->replace($old_pkg_svc);
- eidiot($error) if $error;
+ } );
+ if ( $old_pkg_svc ) {
+ my $myerror = $new_pkg_svc->replace($old_pkg_svc);
+ die $myerror if $myerror;
} else {
- my($error)=$new_pkg_svc->insert;
- eidiot($error) if $error;
+ my $myerror = $new_pkg_svc->insert;
+ die $myerror if $myerror;
}
}
-#$req->cgi->redirect("../../view/part_pkg.cgi?$pkgpart");
-#$req->cgi->redirect("../../edit/part_pkg.cgi?$pkgpart");
-$req->cgi->redirect("../../browse/part_pkg.cgi");
+unless ( $cgi->param('pkgnum') && $cgi->param('pkgnum') =~ /^(\d+)$/ ) {
+ print $cgi->redirect(popurl(3). "browse/part_pkg.cgi");
+} else {
+ my($old_cust_pkg) = qsearchs( 'cust_pkg', { 'pkgnum' => $1 } );
+ my %hash = $old_cust_pkg->hash;
+ $hash{'pkgpart'} = $pkgpart;
+ my($new_cust_pkg) = new FS::cust_pkg \%hash;
+ my $myerror = $new_cust_pkg->replace($old_cust_pkg);
+ die "Error modifying cust_pkg record: $myerror\n" if $myerror;
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?". $new_cust_pkg->custnum);
+}
+
diff --git a/htdocs/edit/process/part_referral.cgi b/htdocs/edit/process/part_referral.cgi
index 08a4c01d0..cde27ede1 100755
--- a/htdocs/edit/process/part_referral.cgi
+++ b/htdocs/edit/process/part_referral.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/part_referral.cgi: Edit referrals (process form)
+# $Id: part_referral.cgi,v 1.6 1999-02-07 09:59:28 ivan Exp $
#
# ivan@sisd.com 98-feb-23
#
@@ -8,38 +8,58 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: part_referral.cgi,v $
+# Revision 1.6 1999-02-07 09:59:28 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.5 1999/01/19 05:13:56 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 22:47:57 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.3 1998/12/30 23:03:30 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.2 1998/12/17 08:40:25 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $refnum $new $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs);
-use FS::part_referral qw(fields);
-use FS::CGI qw(eidiot);
-use FS::CGI qw(eidiot);
-
-my($req)=new CGI::Request; # create form object
+use FS::Record qw(qsearchs fields);
+use FS::part_referral;
+use FS::CGI qw(popurl);
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-my($refnum)=$req->param('refnum');
+$refnum = $cgi->param('refnum');
-my($new)=create FS::part_referral ( {
+$new = new FS::part_referral ( {
map {
- $_, $req->param($_);
+ $_, scalar($cgi->param($_));
} fields('part_referral')
} );
if ( $refnum ) {
- my($old)=qsearchs('part_referral',{'refnum'=>$refnum});
- eidiot("(Old) Record not found!") unless $old;
- my($error)=$new->replace($old);
- eidiot($error) if $error;
+ my $old = qsearchs( 'part_referral', { 'refnum' =>$ refnum } );
+ die "(Old) Record not found!" unless $old;
+ $error = $new->replace($old);
} else {
- my($error)=$new->insert;
- eidiot($error) if $error;
+ $error = $new->insert;
}
+$refnum=$new->refnum;
-$refnum=$new->getfield('refnum');
-$req->cgi->redirect("../../browse/part_referral.cgi");
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "part_referral.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "browse/part_referral.cgi");
+}
diff --git a/htdocs/edit/process/part_svc.cgi b/htdocs/edit/process/part_svc.cgi
index 0f0fbc6e8..0b3e2cd1c 100755
--- a/htdocs/edit/process/part_svc.cgi
+++ b/htdocs/edit/process/part_svc.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/part_svc.cgi: Edit service definitions (process form)
+# $Id: part_svc.cgi,v 1.7 1999-02-07 09:59:29 ivan Exp $
#
# ivan@sisd.com 97-nov-14
#
@@ -8,40 +8,62 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: part_svc.cgi,v $
+# Revision 1.7 1999-02-07 09:59:29 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.6 1999/01/19 05:13:57 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 22:47:58 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.4 1998/12/30 23:03:31 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.3 1998/12/17 08:40:26 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
+# Revision 1.2 1998/11/21 06:43:08 ivan
+# s/CGI::Request/CGI.pm/
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi $svcpart $old $new $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs);
-use FS::part_svc qw(fields);
-use FS::CGI qw(eidiot);
-
-my($req)=new CGI::Request; # create form object
+use FS::Record qw(qsearchs fields);
+use FS::part_svc;
+use FS::CGI qw(popurl);
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-my($svcpart)=$req->param('svcpart');
+$svcpart = $cgi->param('svcpart');
-my($old)=qsearchs('part_svc',{'svcpart'=>$svcpart}) if $svcpart;
+$old = qsearchs('part_svc',{'svcpart'=>$svcpart}) if $svcpart;
-my($new)=create FS::part_svc ( {
+$new = new FS::part_svc ( {
map {
- $_, $req->param($_);
+ $_, scalar($cgi->param($_));
# } qw(svcpart svc svcdb)
} fields('part_svc')
} );
if ( $svcpart ) {
- my($error)=$new->replace($old);
- eidiot($error) if $error;
+ $error = $new->replace($old);
} else {
- my($error)=$new->insert;
- eidiot($error) if $error;
+ $error = $new->insert;
$svcpart=$new->getfield('svcpart');
}
-#$req->cgi->redirect("../../view/part_svc.cgi?$svcpart");
-#$req->cgi->redirect("../../edit/part_svc.cgi?$svcpart");
-$req->cgi->redirect("../../browse/part_svc.cgi");
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "part_svc.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3)."browse/part_svc.cgi");
+}
diff --git a/htdocs/edit/process/svc_acct.cgi b/htdocs/edit/process/svc_acct.cgi
index 8d77ba703..84f93abe8 100755
--- a/htdocs/edit/process/svc_acct.cgi
+++ b/htdocs/edit/process/svc_acct.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# process/svc_acct.cgi: Add/edit a customer (process form)
+# $Id: svc_acct.cgi,v 1.7 1999-08-27 00:26:33 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/svc_acct.cgi
#
-# Note: Should br run setuid root as user nobody.
-#
# ivan@voicenet.com 96-dec-18
#
# Changed /u to /u2
@@ -21,67 +19,78 @@
# Changes to allow page to work at a relative position in server
# Changed 'password' to '_password' because Pg6.3 reserves the password word
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: svc_acct.cgi,v $
+# Revision 1.7 1999-08-27 00:26:33 ivan
+# better error messages
+#
+# Revision 1.6 1999/02/28 00:03:45 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/02/07 09:59:30 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.4 1999/01/19 05:13:58 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1999/01/18 22:47:59 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.2 1998/12/17 08:40:27 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $svcnum $old $new $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs);
+use FS::CGI qw(popurl);
+use FS::Record qw(qsearchs fields);
use FS::svc_acct;
-my($req) = new CGI::Request; # create form object
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-$req->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
-my($svcnum)=$1;
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+$svcnum = $1;
-my($old)=qsearchs('svc_acct',{'svcnum'=>$svcnum}) if $svcnum;
+if ( $svcnum ) {
+ $old = qsearchs('svc_acct', { 'svcnum' => $svcnum } )
+ or die "fatal: can't find account (svcnum $svcnum)!";
+} else {
+ $old = '';
+}
#unmunge popnum
-$req->param('popnum', (split(/:/, $req->param('popnum') ))[0] );
+$cgi->param('popnum', (split(/:/, $cgi->param('popnum') ))[0] );
#unmunge passwd
-if ( $req->param('_password') eq '*HIDDEN*' ) {
- $req->param('_password',$old->getfield('_password'));
+if ( $cgi->param('_password') eq '*HIDDEN*' ) {
+ die "fatal: no previous account to recall hidden password from!" unless $old;
+ $cgi->param('_password',$old->getfield('_password'));
}
-my($new) = create FS::svc_acct ( {
+$new = new FS::svc_acct ( {
map {
- $_, $req->param($_);
- } qw(svcnum pkgnum svcpart username _password popnum uid gid finger dir
- shell quota slipip)
+ $_, scalar($cgi->param($_));
+ #} qw(svcnum pkgnum svcpart username _password popnum uid gid finger dir
+ # shell quota slipip)
+ } ( fields('svc_acct'), qw( pkgnum svcpart ) )
} );
if ( $svcnum ) {
- my($error) = $new->replace($old);
- &idiot($error) if $error;
+ $error = $new->replace($old);
} else {
- my($error) = $new->insert;
- &idiot($error) if $error;
- $svcnum = $new->getfield('svcnum');
+ $error = $new->insert;
+ $svcnum = $new->svcnum;
}
-#no errors, view account
-$req->cgi->redirect("../../view/svc_acct.cgi?" . $svcnum );
-
-sub idiot {
- my($error)=@_;
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error adding/updating account</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error adding/updating account</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and submit the form again.
- </BODY>
-</HTML>
-END
- exit;
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_acct.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "view/svc_acct.cgi?" . $svcnum );
}
diff --git a/htdocs/edit/process/svc_acct_pop.cgi b/htdocs/edit/process/svc_acct_pop.cgi
index 18d7940b4..763bca4a8 100755
--- a/htdocs/edit/process/svc_acct_pop.cgi
+++ b/htdocs/edit/process/svc_acct_pop.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/svc_acct_pop.cgi: Edit POP (process form)
+# $Id: svc_acct_pop.cgi,v 1.6 1999-02-07 09:59:31 ivan Exp $
#
# ivan@sisd.com 98-mar-8
#
@@ -8,36 +8,59 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: svc_acct_pop.cgi,v $
+# Revision 1.6 1999-02-07 09:59:31 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.5 1999/01/19 05:13:59 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 22:48:00 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.3 1998/12/30 23:03:32 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.2 1998/12/17 08:40:28 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $popnum $old $new $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
-use FS::svc_acct_pop qw(fields);
-use FS::CGI qw(eidiot);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::svc_acct_pop;
+use FS::CGI qw(popurl);
-my($req)=new CGI::Request; # create form object
+$cgi = new CGI; # create form object
-&cgisuidsetup($req->cgi);
+&cgisuidsetup($cgi);
-my($popnum)=$req->param('popnum');
+$popnum = $cgi->param('popnum');
-my($old)=qsearchs('svc_acct_pop',{'popnum'=>$popnum}) if $popnum;
+$old = qsearchs('svc_acct_pop',{'popnum'=>$popnum}) if $popnum;
-my($new)=create FS::svc_acct_pop ( {
+$new = new FS::svc_acct_pop ( {
map {
- $_, $req->param($_);
+ $_, scalar($cgi->param($_));
} fields('svc_acct_pop')
} );
if ( $popnum ) {
- my($error)=$new->replace($old);
- eidiot($error) if $error;
+ $error = $new->replace($old);
} else {
- my($error)=$new->insert;
- eidiot($error) if $error;
+ $error = $new->insert;
$popnum=$new->getfield('popnum');
}
-$req->cgi->redirect("../../browse/svc_acct_pop.cgi");
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_acct_pop.cgi?". $cgi->query_string );
+} else {
+ print $cgi->redirect(popurl(3). "browse/svc_acct_pop.cgi");
+}
diff --git a/htdocs/edit/process/svc_acct_sm.cgi b/htdocs/edit/process/svc_acct_sm.cgi
index 9ad546bf4..9c39bb8e5 100755
--- a/htdocs/edit/process/svc_acct_sm.cgi
+++ b/htdocs/edit/process/svc_acct_sm.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# process/svc_acct_sm.cgi: Add/edit a mail alias (process form)
+# $Id: svc_acct_sm.cgi,v 1.6 1999-02-28 00:03:46 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/svc_acct_sm.cgi
#
-# Note: Should br run setuid root as user nobody.
-#
# lots of crufty stuff from svc_acct still in here, and modifications are (unelegantly) disabled.
#
# ivan@voicenet.com 97-jan-6
@@ -22,33 +20,53 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: svc_acct_sm.cgi,v $
+# Revision 1.6 1999-02-28 00:03:46 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/02/07 09:59:32 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.4 1999/01/19 05:14:00 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1999/01/18 22:48:01 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.2 1998/12/17 08:40:29 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $svcnum $old $new $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs);
+use FS::Record qw(qsearchs fields);
use FS::svc_acct_sm;
+use FS::CGI qw(popurl);
-my($req)=new CGI::Request; # create form object
-cgisuidsetup($req->cgi);
+$cgi = new CGI;
+cgisuidsetup($cgi);
-$req->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
-my($svcnum)=$1;
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+$svcnum =$1;
-my($old)=qsearchs('svc_acct_sm',{'svcnum'=>$svcnum}) if $svcnum;
+$old = qsearchs('svc_acct_sm',{'svcnum'=>$svcnum}) if $svcnum;
#unmunge domsvc and domuid
-$req->param('domsvc',(split(/:/, $req->param('domsvc') ))[0] );
-$req->param('domuid',(split(/:/, $req->param('domuid') ))[0] );
+#$cgi->param('domsvc',(split(/:/, $cgi->param('domsvc') ))[0] );
+#$cgi->param('domuid',(split(/:/, $cgi->param('domuid') ))[0] );
-my($new) = create FS::svc_acct_sm ( {
+$new = new FS::svc_acct_sm ( {
map {
- ($_, scalar($req->param($_)));
- } qw(svcnum pkgnum svcpart domuser domuid domsvc)
+ ($_, scalar($cgi->param($_)));
+ #} qw(svcnum pkgnum svcpart domuser domuid domsvc)
+ } ( fields('svc_acct_sm'), qw( pkgnum svcpart ) )
} );
-my($error);
if ( $svcnum ) {
$error = $new->replace($old);
} else {
@@ -56,25 +74,10 @@ if ( $svcnum ) {
$svcnum = $new->getfield('svcnum');
}
-unless ($error) {
- $req->cgi->redirect("../../view/svc_acct_sm.cgi?$svcnum");
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_acct_sm.cgi?". $cgi->query_string );
} else {
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error adding/editing mail alias</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error adding/editing mail alias</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and submit the form again.
- </BODY>
-</HTML>
-END
-
+ print $cgi->redirect(popurl(3). "view/svc_acct_sm.cgi?$svcnum");
}
diff --git a/htdocs/edit/process/svc_domain.cgi b/htdocs/edit/process/svc_domain.cgi
index 0782772dd..e12aa1b55 100755
--- a/htdocs/edit/process/svc_domain.cgi
+++ b/htdocs/edit/process/svc_domain.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# process/svc_domain.cgi: Add a domain (process form)
+# $Id: svc_domain.cgi,v 1.6 1999-02-28 00:03:47 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/svc_domain.cgi
#
-# Note: Should br run setuid root as user nobody.
-#
# lots of yucky stuff in this one... bleachlkjhui!
#
# ivan@voicenet.com 97-jan-6
@@ -18,61 +16,65 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: svc_domain.cgi,v $
+# Revision 1.6 1999-02-28 00:03:47 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/02/07 09:59:33 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.4 1999/01/19 05:14:01 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1999/01/18 22:48:02 ivan
+# s/create/new/g; and use fields('table_name')
+#
+# Revision 1.2 1998/12/17 08:40:30 ivan
+# s/CGI::Request/CGI.pm/; etc
+#
use strict;
-use CGI::Request;
+use vars qw( $cgi $svcnum $new $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs);
+use FS::Record qw(qsearchs fields);
use FS::svc_domain;
+use FS::CGI qw(popurl);
#remove this to actually test the domains!
$FS::svc_domain::whois_hack = 1;
-my($req) = new CGI::Request;
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-$req->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
-my($svcnum)=$1;
+$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!";
+$svcnum = $1;
-my($new) = create FS::svc_domain ( {
+$new = new FS::svc_domain ( {
map {
- $_, $req->param($_);
- } qw(svcnum pkgnum svcpart domain action purpose)
+ $_, scalar($cgi->param($_));
+ #} qw(svcnum pkgnum svcpart domain action purpose)
+ } ( fields('svc_domain'), qw( pkgnum svcpart action purpose ) )
} );
-my($error);
-if ($req->param('legal') ne "Yes") {
+if ($cgi->param('legal') ne "Yes") {
$error = "Customer did not agree to be bound by NSI's ".
qq!<A HREF="http://rs.internic.net/help/agreement.txt">!.
"Domain Name Resgistration Agreement</A>";
-} elsif ($req->param('svcnum')) {
+} elsif ($cgi->param('svcnum')) {
$error="Can't modify a domain!";
} else {
$error=$new->insert;
$svcnum=$new->svcnum;
}
-unless ($error) {
- $req->cgi->redirect("../../view/svc_domain.cgi?$svcnum");
+if ($error) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "svc_domain.cgi?". $cgi->query_string );
} else {
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error adding domain</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error adding domain</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and submit the form again.
- </BODY>
-</HTML>
-END
-
+ print $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum");
}
-
diff --git a/htdocs/edit/svc_acct.cgi b/htdocs/edit/svc_acct.cgi
index 61d0fdc28..963bc1edf 100755
--- a/htdocs/edit/svc_acct.cgi
+++ b/htdocs/edit/svc_acct.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# svc_acct.cgi: Add/edit account (output form)
+# $Id: svc_acct.cgi,v 1.10 1999-04-14 11:27:06 ivan Exp $
#
# Usage: svc_acct.cgi {svcnum} | pkgnum{pkgnum}-svcpart{svcpart}
# http://server.name/path/svc_acct.cgi? {svcnum} | pkgnum{pkgnum}-svcpart{svcpart}
#
-# Note: Should be run setuid freeside as user nobody
-#
# ivan@voicenet.com 96-dec-18
#
# rewrite ivan@sisd.com 98-mar-8
@@ -16,100 +14,139 @@
# bmccane@maxbaud.net 98-apr-3
#
# use conf/shells and dbdef username length ivan@sisd.com 98-jul-13
+#
+# $Log: svc_acct.cgi,v $
+# Revision 1.10 1999-04-14 11:27:06 ivan
+# showpasswords config option to show passwords
+#
+# Revision 1.9 1999/02/28 00:03:37 ivan
+# removed misleading comments
+#
+# Revision 1.8 1999/02/23 08:09:22 ivan
+# beginnings of one-screen new customer entry and some other miscellania
+#
+# Revision 1.7 1999/02/07 09:59:22 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.6 1999/01/19 05:13:43 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:32 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1998/12/30 23:03:22 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.3 1998/12/17 06:17:08 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw( $conf $cgi @shells $action $svcnum $svc_acct $pkgnum $svcpart
+ $part_svc $svc $otaker $username $password $ulen $ulen2 $p1
+ $popnum $uid $gid $finger $dir $shell $quota $slipip );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup getotaker);
-use FS::Record qw(qsearch qsearchs);
-use FS::svc_acct qw(fields);
-
-my($shells)="/var/spool/freeside/conf/shells";
-open(SHELLS,$shells) or die "Can't open $shells: $!";
-my(@shells)=map {
- /^([\/\w]*)$/ or die "Illegal shell in conf/shells!";
- $1;
-} grep $_ !~ /^#/, <SHELLS>;
-
-my($cgi) = new CGI::Base;
-$cgi->get;
-&cgisuidsetup($cgi);
-
-my($action,$svcnum,$svc_acct,$pkgnum,$svcpart,$part_svc);
+use FS::CGI qw(header popurl);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::svc_acct;
+use FS::Conf;
-if ( $QUERY_STRING =~ /^(\d+)$/ ) { #editing
-
- $svcnum=$1;
- $svc_acct=qsearchs('svc_acct',{'svcnum'=>$svcnum})
- or die "Unknown (svc_acct) svcnum!";
-
- my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
- or die "Unknown (cust_svc) svcnum!";
+$cgi = new CGI;
+&cgisuidsetup($cgi);
- $pkgnum=$cust_svc->pkgnum;
- $svcpart=$cust_svc->svcpart;
+$conf = new FS::Conf;
+@shells = $conf->config('shells');
+if ( $cgi->param('error') ) {
+ $svc_acct = new FS::svc_acct ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_acct')
+ } );
+ $svcnum = $svc_acct->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
$part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
die "No part_svc entry!" unless $part_svc;
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_acct=qsearchs('svc_acct',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_acct) svcnum!";
- $action="Edit";
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
-} else { #adding
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
- $svc_acct=create FS::svc_acct({});
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
- foreach $_ (split(/-/,$QUERY_STRING)) {
- $pkgnum=$1 if /^pkgnum(\d+)$/;
- $svcpart=$1 if /^svcpart(\d+)$/;
- }
- $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
- die "No part_svc entry!" unless $part_svc;
+ } else { #adding
- $svcnum='';
+ $svc_acct = new FS::svc_acct({});
- #set gecos
- my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
- if ($cust_pkg) {
- my($cust_main)=qsearchs('cust_main',{'custnum'=> $cust_pkg->custnum } );
- $svc_acct->setfield('finger',
- $cust_main->getfield('first') . " " . $cust_main->getfield('last')
- ) ;
- }
+ foreach $_ (split(/-/,$query)) {
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
+
+ $svcnum='';
+
+ #set gecos
+ my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+ if ($cust_pkg) {
+ my($cust_main)=qsearchs('cust_main',{'custnum'=> $cust_pkg->custnum } );
+ $svc_acct->setfield('finger',
+ $cust_main->getfield('first') . " " . $cust_main->getfield('last')
+ ) ;
+ }
- #set fixed and default fields from part_svc
- my($field);
- foreach $field ( fields('svc_acct') ) {
- if ( $part_svc->getfield('svc_acct__'. $field. '_flag') ne '' ) {
- $svc_acct->setfield($field,$part_svc->getfield('svc_acct__'. $field) );
+ #set fixed and default fields from part_svc
+ my($field);
+ foreach $field ( fields('svc_acct') ) {
+ if ( $part_svc->getfield('svc_acct__'. $field. '_flag') ne '' ) {
+ $svc_acct->setfield($field,$part_svc->getfield('svc_acct__'. $field) );
+ }
}
+
}
+}
+$action = $svcnum ? 'Edit' : 'Add';
- $action="Add";
+$svc = $part_svc->getfield('svc');
-}
+$otaker = getotaker;
-my($svc)=$part_svc->getfield('svc');
+$username = $svc_acct->username;
+if ( $svc_acct->_password ) {
+ if ( $conf->exists('showpasswords') ) {
+ $password = $svc_acct->_password;
+ } else {
+ $password = "*HIDDEN*";
+ }
+} else {
+ $password = '';
+}
-my($otaker)=getotaker;
+$ulen = $svc_acct->dbdef_table->column('username')->length;
+$ulen2 = $ulen+2;
-my($username,$password)=(
- $svc_acct->username,
- $svc_acct->_password ? "*HIDDEN*" : '',
-);
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("$action $svc account");
-my($ulen)=$svc_acct->dbdef_table->column('username')->length;
-my($ulen2)=$ulen+2;
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-SendHeaders();
print <<END;
-<HTML>
- <HEAD>
- <TITLE>$action $svc account</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>$action $svc account</H1>
- </CENTER><HR>
- <FORM ACTION="process/svc_acct.cgi" METHOD=POST>
+ <FORM ACTION="${p1}process/svc_acct.cgi" METHOD=POST>
<INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">
<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">
<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">
@@ -121,7 +158,7 @@ Username:
END
#pop
-my($popnum)=$svc_acct->popnum || 0;
+$popnum = $svc_acct->popnum || 0;
if ( $part_svc->svc_acct__popnum_flag eq "F" ) {
print qq!<INPUT TYPE="hidden" NAME="popnum" VALUE="$popnum">!;
} else {
@@ -132,14 +169,14 @@ if ( $part_svc->svc_acct__popnum_flag eq "F" ) {
$svc_acct_pop->popnum, ": ",
$svc_acct_pop->city, ", ",
$svc_acct_pop->state,
- "(", $svc_acct_pop->ac, ")/",
+ " (", $svc_acct_pop->ac, ")/",
$svc_acct_pop->exch, "\n"
;
}
print "</SELECT>";
}
-my($uid,$gid,$finger,$dir)=(
+($uid,$gid,$finger,$dir)=(
$svc_acct->uid,
$svc_acct->gid,
$svc_acct->finger,
@@ -153,7 +190,7 @@ print <<END;
<INPUT TYPE="hidden" NAME="dir" VALUE="$dir">
END
-my($shell)=$svc_acct->shell;
+$shell = $svc_acct->shell;
if ( $part_svc->svc_acct__shell_flag eq "F" ) {
print qq!<INPUT TYPE="hidden" NAME="shell" VALUE="$shell">!;
} else {
@@ -166,7 +203,7 @@ if ( $part_svc->svc_acct__shell_flag eq "F" ) {
print "</SELECT>";
}
-my($quota,$slipip)=(
+($quota,$slipip)=(
$svc_acct->quota,
$svc_acct->slipip,
);
@@ -180,7 +217,7 @@ if ( $part_svc->svc_acct__slipip_flag eq "F" ) {
}
#submit
-print qq!<P><CENTER><INPUT TYPE="submit" VALUE="Submit"></CENTER>!;
+print qq!<P><INPUT TYPE="submit" VALUE="Submit">!;
print <<END;
</FORM>
diff --git a/htdocs/edit/svc_acct_pop.cgi b/htdocs/edit/svc_acct_pop.cgi
index 46d803f07..1797b2b8e 100755
--- a/htdocs/edit/svc_acct_pop.cgi
+++ b/htdocs/edit/svc_acct_pop.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# svc_acct_pop.cgi: Add/Edit pop (output form)
+# $Id: svc_acct_pop.cgi,v 1.9 2000-01-28 23:02:48 ivan Exp $
#
# ivan@sisd.com 98-mar-8
#
@@ -8,38 +8,72 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: svc_acct_pop.cgi,v $
+# Revision 1.9 2000-01-28 23:02:48 ivan
+# track full phone number
+#
+# Revision 1.8 1999/02/23 08:09:23 ivan
+# beginnings of one-screen new customer entry and some other miscellania
+#
+# Revision 1.7 1999/02/07 09:59:23 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.6 1999/01/19 05:13:44 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:33 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1998/12/23 02:57:45 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.3 1998/12/17 06:17:10 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.2 1998/11/13 09:56:47 ivan
+# change configuration file layout to support multiple distinct databases (with
+# own set of config files, export, etc.)
+#
use strict;
-use CGI::Base;
+use vars qw( $cgi $svc_acct_pop $action $query $hashref $p1 );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::CGI qw(header menubar popurl);
use FS::svc_acct_pop;
-use FS::CGI qw(header menubar);
-
-my($cgi) = new CGI::Base;
-$cgi->get;
-
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-
-my($svc_acct_pop,$action);
-if ( $cgi->var('QUERY_STRING') =~ /^(\d+)$/ ) { #editing
+if ( $cgi->param('error') ) {
+ $svc_acct_pop = new FS::svc_acct_pop ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_acct_pop')
+ } );
+} elsif ( $cgi->keywords ) { #editing
+ my($query)=$cgi->keywords;
+ $query =~ /^(\d+)$/;
$svc_acct_pop=qsearchs('svc_acct_pop',{'popnum'=>$1});
- $action='Edit';
} else { #adding
- $svc_acct_pop=create FS::svc_acct_pop {};
- $action='Add';
+ $svc_acct_pop = new FS::svc_acct_pop {};
}
-my($hashref)=$svc_acct_pop->hashref;
+$action = $svc_acct_pop->popnum ? 'Edit' : 'Add';
+$hashref = $svc_acct_pop->hashref;
-print header("$action POP", menubar(
- 'Main Menu' => '../',
- 'View all POPs' => "../browse/svc_acct_pop.cgi",
-)), <<END;
- <FORM ACTION="process/svc_acct_pop.cgi" METHOD=POST>
-END
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("$action POP", menubar(
+ 'Main Menu' => popurl(2),
+ 'View all POPs' => popurl(2). "browse/svc_acct_pop.cgi",
+));
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/svc_acct_pop.cgi" METHOD=POST>!;
#display
@@ -49,9 +83,10 @@ print qq!<INPUT TYPE="hidden" NAME="popnum" VALUE="$hashref->{popnum}">!,
print <<END;
<PRE>
City <INPUT TYPE="text" NAME="city" SIZE=32 VALUE="$hashref->{city}">
-State <INPUT TYPE="text" NAME="state" SIZE=3 MAXLENGTH=2 VALUE="$hashref->{state}">
+State <INPUT TYPE="text" NAME="state" SIZE=16 MAXLENGTH=16 VALUE="$hashref->{state}">
Area Code <INPUT TYPE="text" NAME="ac" SIZE=4 MAXLENGTH=3 VALUE="$hashref->{ac}">
Exchange <INPUT TYPE="text" NAME="exch" SIZE=4 MAXLENGTH=3 VALUE="$hashref->{exch}">
+Local <INPUT TYPE="text" NAME="loc" SIZE=5 MAXLENGTH=4 VALUE="$hashref->{loc}">
</PRE>
END
diff --git a/htdocs/edit/svc_acct_sm.cgi b/htdocs/edit/svc_acct_sm.cgi
index 45a8eb8fc..cb7cbfae0 100755
--- a/htdocs/edit/svc_acct_sm.cgi
+++ b/htdocs/edit/svc_acct_sm.cgi
@@ -1,14 +1,12 @@
#!/usr/bin/perl -Tw
#
-# svc_acct_sm.cgi: Add/edit a mail alias (output form)
+# $Id: svc_acct_sm.cgi,v 1.9 1999-02-28 00:03:38 ivan Exp $
#
# Usage: svc_acct_sm.cgi {svcnum} | pkgnum{pkgnum}-svcpart{svcpart}
# http://server.name/path/svc_acct_sm.cgi? {svcnum} | pkgnum{pkgnum}-svcpart{svcpart}
#
# use {svcnum} for edit, pkgnum{pkgnum}-svcpart{svcpart} for add
#
-# Note: Should be run setuid freeside as user nobody.
-#
# should error out in a more CGI-friendly way, and should have more error checking (sigh).
#
# ivan@voicenet.com 97-jan-5
@@ -33,71 +31,102 @@
# rewrite ivan@sisd.com 98-mar-15
#
# /var/spool/freeside/conf/domain ivan@sisd.com 98-jul-26
+#
+# $Log: svc_acct_sm.cgi,v $
+# Revision 1.9 1999-02-28 00:03:38 ivan
+# removed misleading comments
+#
+# Revision 1.8 1999/02/07 09:59:24 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.7 1999/01/19 05:13:45 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 09:41:34 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.5 1998/12/30 23:03:24 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.4 1998/12/23 02:58:45 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.3 1998/12/17 06:17:11 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.2 1998/12/16 05:19:15 ivan
+# use FS::Conf
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw( $conf $cgi $mydomain $action $svcnum $svc_acct_sm $pkgnum $svcpart
+ $part_svc $query %username %domain $p1 $domuser $domsvc $domuid );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearch qsearchs);
-use FS::svc_acct_sm qw(fields);
-
-my($conf_domain)="/var/spool/freeside/conf/domain";
-open(DOMAIN,$conf_domain) or die "Can't open $conf_domain: $!";
-my($mydomain)=map {
- /^(.*)$/ or die "Illegal line in $conf_domain!"; #yes, we trust the file
- $1
-} grep $_ !~ /^(#|$)/, <DOMAIN>;
-close DOMAIN;
-
-my($cgi) = new CGI::Base;
-$cgi->get;
-&cgisuidsetup($cgi);
-
-SendHeaders(); # one guess.
+use FS::CGI qw(header popurl);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::svc_acct_sm;
+use FS::Conf;
-my($action,$svcnum,$svc_acct_sm,$pkgnum,$svcpart,$part_svc);
-if ( $QUERY_STRING =~ /^(\d+)$/ ) { #editing
-
- $svcnum=$1;
- $svc_acct_sm=qsearchs('svc_acct_sm',{'svcnum'=>$svcnum})
- or die "Unknown (svc_acct_sm) svcnum!";
+$cgi = new CGI;
+&cgisuidsetup($cgi);
- my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
- or die "Unknown (cust_svc) svcnum!";
+$conf = new FS::Conf;
+$mydomain = $conf->config('domain');
- $pkgnum=$cust_svc->pkgnum;
- $svcpart=$cust_svc->svcpart;
-
+if ( $cgi->param('error') ) {
+ $svc_acct_sm = new FS::svc_acct_sm ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_acct_sm')
+ } );
+ $svcnum = $svc_acct_sm->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
$part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
die "No part_svc entry!" unless $part_svc;
+} else {
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_acct_sm=qsearchs('svc_acct_sm',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_acct_sm) svcnum!";
- $action="Edit";
-
-} else { #adding
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
- $svc_acct_sm=create FS::svc_acct_sm({});
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
+
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
- foreach $_ (split(/-/,$QUERY_STRING)) { #get & untaint pkgnum & svcpart
- $pkgnum=$1 if /^pkgnum(\d+)$/;
- $svcpart=$1 if /^svcpart(\d+)$/;
- }
- $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
- die "No part_svc entry!" unless $part_svc;
+ } else { #adding
- $svcnum='';
+ $svc_acct_sm = new FS::svc_acct_sm({});
- #set fixed and default fields from part_svc
- my($field);
- foreach $field ( fields('svc_acct_sm') ) {
- if ( $part_svc->getfield('svc_acct_sm__'. $field. '_flag') ne '' ) {
- $svc_acct_sm->setfield($field,$part_svc->getfield('svc_acct_sm__'. $field) );
+ foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
}
- }
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
- $action='Add';
+ $svcnum='';
+ #set fixed and default fields from part_svc
+ my($field);
+ foreach $field ( fields('svc_acct_sm') ) {
+ if ( $part_svc->getfield('svc_acct_sm__'. $field. '_flag') ne '' ) {
+ $svc_acct_sm->setfield($field,$part_svc->getfield('svc_acct_sm__'. $field) );
+ }
+ }
+
+ }
}
+$action = $svc_acct_sm->svcnum ? 'Edit' : 'Add';
-my(%username,%domain);
if ($pkgnum) {
#find all possible uids (and usernames)
@@ -155,17 +184,14 @@ if ($pkgnum) {
die "\$action eq Add, but \$pkgnum is null!\n";
}
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Mail Alias $action</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Mail Alias $action</H1>
- </CENTER>
- <FORM ACTION="process/svc_acct_sm.cgi" METHOD=POST>
-END
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("Mail Alias $action", '');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print qq!<FORM ACTION="${p1}process/svc_acct_sm.cgi" METHOD=POST>!;
#display
@@ -182,7 +208,7 @@ print qq!<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">!;
#svcpart
print qq!<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">!;
-my($domuser,$domsvc,$domuid)=(
+($domuser,$domsvc,$domuid)=(
$svc_acct_sm->domuser,
$svc_acct_sm->domsvc,
$svc_acct_sm->domuid,
@@ -194,14 +220,16 @@ print qq!\n\nMail to <INPUT TYPE="text" NAME="domuser" VALUE="$domuser"> <I>( *
#domsvc
print qq! \@ <SELECT NAME="domsvc" SIZE=1>!;
foreach $_ (keys %domain) {
- print "<OPTION", $_ eq $domsvc ? " SELECTED" : "", ">$_: $domain{$_}";
+ print "<OPTION", $_ eq $domsvc ? " SELECTED" : "",
+ qq! VALUE="$_">$domain{$_}!;
}
print "</SELECT>";
#uid
print qq!\nforwards to <SELECT NAME="domuid" SIZE=1>!;
foreach $_ (keys %username) {
- print "<OPTION", ($_ eq $domuid) ? " SELECTED" : "", ">$_: $username{$_}";
+ print "<OPTION", ($_ eq $domuid) ? " SELECTED" : "",
+ qq! VALUE="$_">$username{$_}!;
}
print "</SELECT>\@$mydomain mailbox.";
diff --git a/htdocs/edit/svc_domain.cgi b/htdocs/edit/svc_domain.cgi
index 0717a2c09..6b5eff560 100755
--- a/htdocs/edit/svc_domain.cgi
+++ b/htdocs/edit/svc_domain.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# svc_domain.cgi: Add domain (output form)
+# $Id: svc_domain.cgi,v 1.9 1999-02-28 00:03:39 ivan Exp $
#
# Usage: svc_domain.cgi pkgnum{pkgnum}-svcpart{svcpart}
# http://server.name/path/svc_domain.cgi?pkgnum{pkgnum}-svcpart{svcpart}
#
-# Note: Should be run setuid freeside as user nobody
-#
# ivan@voicenet.com 97-jan-5 -> 97-jan-6
#
# changes for domain template 3.5
@@ -15,92 +13,137 @@
# rewrite ivan@sisd.com 98-mar-14
#
# no GOV in instructions ivan@sisd.com 98-jul-17
+#
+# $Log: svc_domain.cgi,v $
+# Revision 1.9 1999-02-28 00:03:39 ivan
+# removed misleading comments
+#
+# Revision 1.8 1999/02/07 09:59:25 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.7 1999/01/19 05:13:46 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 09:41:35 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.5 1998/12/30 23:03:25 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.4 1998/12/23 03:00:16 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.3 1998/12/17 06:17:12 ivan
+# fix double // in relative URLs, s/CGI::Base/CGI/;
+#
+# Revision 1.2 1998/11/13 09:56:48 ivan
+# change configuration file layout to support multiple distinct databases (with
+# own set of config files, export, etc.)
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw( $cgi $action $svcnum $svc_domain $pkgnum $svcpart $part_svc
+ $svc $otaker $domain $p1 $kludge_action $purpose );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup getotaker);
-use FS::Record qw(qsearch qsearchs);
-use FS::svc_domain qw(fields);
+use FS::CGI qw(header popurl);
+use FS::Record qw(qsearch qsearchs fields);
+use FS::svc_domain;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
-my($action,$svcnum,$svc_domain,$pkgnum,$svcpart,$part_svc);
-
-if ( $QUERY_STRING =~ /^(\d+)$/ ) { #editing
-
- $svcnum=$1;
- $svc_domain=qsearchs('svc_domain',{'svcnum'=>$svcnum})
- or die "Unknown (svc_domain) svcnum!";
-
- my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
- or die "Unknown (cust_svc) svcnum!";
+if ( $cgi->param('error') ) {
+ $svc_domain = new FS::svc_domain ( {
+ map { $_, scalar($cgi->param($_)) } fields('svc_domain')
+ } );
+ $svcnum = $svc_domain->svcnum;
+ $pkgnum = $cgi->param('pkgnum');
+ $svcpart = $cgi->param('svcpart');
+ $kludge_action = $cgi->param('action');
+ $purpose = $cgi->param('purpose');
+ $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } );
+ die "No part_svc entry!" unless $part_svc;
+} else {
+ $kludge_action = '';
+ $purpose = '';
+ my($query) = $cgi->keywords;
+ if ( $query =~ /^(\d+)$/ ) { #editing
+ $svcnum=$1;
+ $svc_domain=qsearchs('svc_domain',{'svcnum'=>$svcnum})
+ or die "Unknown (svc_domain) svcnum!";
- $pkgnum=$cust_svc->pkgnum;
- $svcpart=$cust_svc->svcpart;
+ my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum})
+ or die "Unknown (cust_svc) svcnum!";
- $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
- die "No part_svc entry!" unless $part_svc;
+ $pkgnum=$cust_svc->pkgnum;
+ $svcpart=$cust_svc->svcpart;
- $action="Edit";
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
-} else { #adding
+ } else { #adding
- $svc_domain=create FS::svc_domain({});
+ $svc_domain = new FS::svc_domain({});
- foreach $_ (split(/-/,$QUERY_STRING)) {
- $pkgnum=$1 if /^pkgnum(\d+)$/;
- $svcpart=$1 if /^svcpart(\d+)$/;
- }
- $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
- die "No part_svc entry!" unless $part_svc;
+ foreach $_ (split(/-/,$query)) {
+ $pkgnum=$1 if /^pkgnum(\d+)$/;
+ $svcpart=$1 if /^svcpart(\d+)$/;
+ }
+ $part_svc=qsearchs('part_svc',{'svcpart'=>$svcpart});
+ die "No part_svc entry!" unless $part_svc;
- $svcnum='';
+ $svcnum='';
- #set fixed and default fields from part_svc
- my($field);
- foreach $field ( fields('svc_domain') ) {
- if ( $part_svc->getfield('svc_domain__'. $field. '_flag') ne '' ) {
- $svc_domain->setfield($field,$part_svc->getfield('svc_domain__'. $field) );
+ #set fixed and default fields from part_svc
+ my($field);
+ foreach $field ( fields('svc_domain') ) {
+ if ( $part_svc->getfield('svc_domain__'. $field. '_flag') ne '' ) {
+ $svc_domain->setfield($field,$part_svc->getfield('svc_domain__'. $field) );
+ }
}
+
}
+}
+$action = $svcnum ? 'Edit' : 'Add';
- $action="Add";
+$svc = $part_svc->getfield('svc');
-}
+$otaker = getotaker;
-my($svc)=$part_svc->getfield('svc');
+$domain = $svc_domain->domain;
-my($otaker)=getotaker;
+$p1 = popurl(1);
+print $cgi->header( '-expires' => 'now' ), header("$action $svc", '');
-my($domain)=(
- $svc_domain->domain,
-);
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
-SendHeaders();
print <<END;
-<HTML>
- <HEAD>
- <TITLE>$action $svc</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>$action $svc</H1>
- </CENTER><HR>
- <FORM ACTION="process/svc_domain.cgi" METHOD=POST>
+ <FORM ACTION="${p1}process/svc_domain.cgi" METHOD=POST>
<INPUT TYPE="hidden" NAME="svcnum" VALUE="$svcnum">
<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">
<INPUT TYPE="hidden" NAME="svcpart" VALUE="$svcpart">
- <INPUT TYPE="radio" NAME="action" VALUE="N">New
- <BR><INPUT TYPE="radio" NAME="action" VALUE="M">Transfer
+END
+print qq!<INPUT TYPE="radio" NAME="action" VALUE="N"!;
+print ' CHECKED' if $kludge_action eq 'N';
+print qq!>New!;
+print qq!<BR><INPUT TYPE="radio" NAME="action" VALUE="M"!;
+print ' CHECKED' if $kludge_action eq 'M';
+print qq!>Transfer!;
+
+print <<END;
<P>Customer agrees to be bound by NSI's
<A HREF="http://rs.internic.net/help/agreement.txt">
Domain Name Registration Agreement</A>
<SELECT NAME="legal" SIZE=1><OPTION SELECTED>No<OPTION>Yes</SELECT>
<P>Domain <INPUT TYPE="text" NAME="domain" VALUE="$domain" SIZE=28 MAXLENGTH=26>
-<BR>Purpose/Description: <INPUT TYPE="text" NAME="purpose" VALUE="" SIZE=64>
+<BR>Purpose/Description: <INPUT TYPE="text" NAME="purpose" VALUE="$purpose" SIZE=64>
<P><CENTER><INPUT TYPE="submit" VALUE="Submit"></CENTER>
<UL>
<LI>COM is for commercial, for-profit organziations
@@ -112,7 +155,8 @@ Domain Name Registration Agreement</A>
</UL>
US state and local government agencies, schools, libraries, museums, and individuals should register under the US domain. See RFC 1480 for a complete description of the US domain
and registration procedures.
-<P>GOV registrations are limited to top-level US Federal Government agencies (see RFC 1816).
+<!-- <P>GOV registrations are limited to top-level US Federal Government agencies (see RFC 1816).
+!-->
</FORM>
</BODY>
</HTML>
diff --git a/htdocs/images/sisd.jpg b/htdocs/images/sisd.jpg
deleted file mode 100755
index 908a5eaff..000000000
--- a/htdocs/images/sisd.jpg
+++ /dev/null
Binary files differ
diff --git a/htdocs/index.html b/htdocs/index.html
index de0667e59..052aed3ed 100755
--- a/htdocs/index.html
+++ b/htdocs/index.html
@@ -14,16 +14,17 @@
</td></tr>
</table>
<A HREF="http://www.sisd.com/freeside">
- Information
+ Freeside home page
</A>
<BR><A HREF="docs/">
Documentation
</A>
</P>
<HR>
- <H3><A HREF="edit/cust_main.cgi">New Customer</A></H3>
- <A NAME="search"><H3>Search</H3></A>
- <MENU>
+ <ul>
+ <li><A HREF="edit/cust_main.cgi">New Customer</A>
+ <li><A NAME="search">Search</A>
+ <ul>
<LI><A HREF="search/cust_main.html">
customers (by last name and/or company)
</A>
@@ -32,9 +33,9 @@
<LI><A HREF="search/svc_domain.html">domains (by domain)</A>
<LI><A HREF="search/svc_acct_sm.html">mail aliases (by domain, and optionally username)</A>
<LI><A HREF="search/cust_bill.html">invoices (by invoice number)</A>
- </MENU>
- <A NAME="browse"><H3>Browse</H3></A>
- <MENU>
+ </ul>
+ <li><A NAME="browse">Browse</A>
+ <ul>
<LI><A HREF="search/cust_main.cgi?custnum">customers (by customer number)</A>
<LI><A HREF="search/cust_main.cgi?last">customers (by last name)</A>
<LI><A HREF="search/cust_main.cgi?company">customers (by company)</A>
@@ -50,15 +51,15 @@
<LI><A HREF="search/svc_domain.cgi?domain">domains (by domain)</A>
<LI><A HREF="search/svc_domain.cgi?UN_svcnum">unlinked domains (by service number)</A>
<LI><A HREF="search/svc_domain.cgi?UN_domain">unlinked domains (by domain)</A>
- </MENU>
- <A NAME="admin"><H3>Administration</H3></a>
- <MENU>
+ </ul>
+ <li><A NAME="admin">Administration</a>
+ <ul>
<LI><A HREF="browse/part_svc.cgi">
- View/Edit services
+ View/Edit service definitions
</A>
- Services are items you offer to your customers.
<LI><A HREF="browse/part_pkg.cgi">
- View/Edit packages
+ View/Edit package definitions
</A>
- One or more services are grouped together into a package and
given pricing information. Customers purchase packages, not
@@ -66,31 +67,28 @@
<LI><A HREF="browse/agent_type.cgi">
View/Edit agent types
</A>
- - Agent types define groups of packages that you can then assign
- to particular agents.
+ - Agent types define groups of package definitions that you can
+ then assign to particular agents.
<LI><A HREF="browse/agent.cgi">
View/Edit agents
</A>
- Agents are resellers of your service. Agents may be limited
- to a subset of your full offerings (via their agent type).
- <BR>
+ to a subset of your full offerings (via their type).
<LI><A HREF="browse/part_referral.cgi">
View/Edit referrals
</A>
- Where a customer heard about your service. Tracked for
informational purposes.
- <BR>
<LI><A HREF="browse/cust_main_county.cgi">
View/Edit locales and tax rates
</A>
- - Change tax rates by state, or break down a state into counties
- and assign different tax rates to each county.
- <BR>
+ - Change tax rates, or break down a country into states, or a state
+ into counties and assign different tax rates to each.
<LI><A HREF="browse/svc_acct_pop.cgi">
View/Edit POPs
</A>
- Points of Presence
- </MENU>
- </FONT>
+ </ul>
+ </ul>
</BODY>
</HTML>
diff --git a/htdocs/misc/bill.cgi b/htdocs/misc/bill.cgi
index d41f6d1c9..52323ba59 100755
--- a/htdocs/misc/bill.cgi
+++ b/htdocs/misc/bill.cgi
@@ -1,36 +1,50 @@
#!/usr/bin/perl -Tw
#
+# $Id: bill.cgi,v 1.5 1999-08-12 04:32:21 ivan Exp $
+#
# s/FS:Search/FS::Record/ and cgisuidsetup($cgi) ivan@sisd.com 98-mar-13
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: bill.cgi,v $
+# Revision 1.5 1999-08-12 04:32:21 ivan
+# hidecancelledcustomers
+#
+# Revision 1.4 1999/01/19 05:14:02 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1998/12/23 03:01:13 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:12:41 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw( $cgi $query $custnum $cust_main $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl eidiot);
use FS::Record qw(qsearchs);
-use FS::Bill;
+use FS::cust_main;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
#untaint custnum
-$QUERY_STRING =~ /^(\d*)$/;
-my($custnum)=$1;
-my($cust_main)=qsearchs('cust_main',{'custnum'=>$custnum});
+($query) = $cgi->keywords;
+$query =~ /^(\d*)$/;
+$custnum = $1;
+$cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
die "Can't find customer!\n" unless $cust_main;
-# ?
-bless($cust_main,"FS::Bill");
-
-my($error);
-
$error = $cust_main->bill(
# 'time'=>$time
);
-&idiot($error) if $error;
+&eidiot($error) if $error;
$error = $cust_main->collect(
# 'invoice-time'=>$time,
@@ -38,29 +52,7 @@ $error = $cust_main->collect(
'batch_card'=> 'no',
'report_badcard'=> 'yes',
);
-&idiot($error) if $error;
-
-$cgi->redirect("../view/cust_main.cgi?$custnum#history");
-
-sub idiot {
- my($error)=@_;
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error billing customer</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error billing customer</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- </BODY>
-</HTML>
-END
-
- exit;
+&eidiot($error) if $error;
-}
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?$custnum");
diff --git a/htdocs/misc/cancel-unaudited.cgi b/htdocs/misc/cancel-unaudited.cgi
index 929274f38..78b7d3175 100755
--- a/htdocs/misc/cancel-unaudited.cgi
+++ b/htdocs/misc/cancel-unaudited.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# cancel-unaudited.cgi: Cancel an unaudited account
+# $Id: cancel-unaudited.cgi,v 1.6 1999-02-28 00:03:48 ivan Exp $
#
# Usage: cancel-unaudited.cgi svcnum
# http://server.name/path/cancel-unaudited.cgi pkgnum
#
-# Note: Should be run setuid freeside as user nobody
-#
# ivan@voicenet.com 97-apr-23
#
# rewrote for new API
@@ -16,29 +14,49 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: cancel-unaudited.cgi,v $
+# Revision 1.6 1999-02-28 00:03:48 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/02/07 09:59:34 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.4 1999/01/19 05:14:03 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1998/12/23 03:02:05 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:12:42 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use vars qw( $cgi $query $svcnum $svc_acct $cust_svc $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl eidiot);
use FS::Record qw(qsearchs);
use FS::cust_svc;
use FS::svc_acct;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
#untaint svcnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($svcnum)=$1;
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+$svcnum = $1;
-my($svc_acct) = qsearchs('svc_acct',{'svcnum'=>$svcnum});
-&idiot("Unknown svcnum!") unless $svc_acct;
+$svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum});
+die "Unknown svcnum!" unless $svc_acct;
-my($cust_svc) = qsearchs('cust_svc',{'svcnum'=>$svcnum});
-&idiot(qq!This account has already been audited. Cancel the
- <A HREF="../view/cust_pkg.cgi?! . $cust_svc->getfield('pkgnum') .
+$cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+&eidiot(qq!This account has already been audited. Cancel the
+ <A HREF="!. popurl(2). qq!view/cust_pkg.cgi?! . $cust_svc->getfield('pkgnum') .
qq!pkgnum"> package</A> instead.!)
if $cust_svc->getfield('pkgnum') ne '';
@@ -48,38 +66,13 @@ local $SIG{QUIT} = 'IGNORE';
local $SIG{TERM} = 'IGNORE';
local $SIG{TSTP} = 'IGNORE';
-my($error);
-
-bless($svc_acct,"FS::svc_acct");
$error = $svc_acct->cancel;
-&idiot($error) if $error;
+&eidiot($error) if $error;
$error = $svc_acct->delete;
-&idiot($error) if $error;
+&eidiot($error) if $error;
-bless($cust_svc,"FS::cust_svc");
$error = $cust_svc->delete;
-&idiot($error) if $error;
-
-$cgi->redirect("../");
+&eidiot($error) if $error;
-sub idiot {
- my($error)=@_;
- SendHeaders();
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error cancelling account</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Error cancelling account</H1>
- </CENTER>
- <HR>
- There has been an error cancelling this acocunt: $error
- </BODY>
- </HEAD>
-</HTML>
-END
- exit;
-}
+print $cgi->redirect(popurl(2));
diff --git a/htdocs/misc/cancel_pkg.cgi b/htdocs/misc/cancel_pkg.cgi
index 6702a0351..7bbcf6e7f 100755
--- a/htdocs/misc/cancel_pkg.cgi
+++ b/htdocs/misc/cancel_pkg.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# cancel_pkg.cgi: Cancel a package
+# $Id: cancel_pkg.cgi,v 1.6 1999-04-08 10:35:02 ivan Exp $
#
# Usage: cancel_pkg.cgi pkgnum
# http://server.name/path/cancel_pkg.cgi pkgnum
#
-# Note: Should be run setuid freeside as user nobody
-#
# IT DOESN'T RUN THE APPROPRIATE PROGRAMS YET!!!!
#
# probably should generalize this to do cancels, suspensions, unsuspensions, etc.
@@ -27,28 +25,47 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: cancel_pkg.cgi,v $
+# Revision 1.6 1999-04-08 10:35:02 ivan
+# import necessary subroutines from FS::CGI
+#
+# Revision 1.5 1999/02/28 00:03:49 ivan
+# removed misleading comments
+#
+# Revision 1.4 1999/01/19 05:14:04 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1998/12/23 03:02:54 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:12:43 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use vars qw ( $cgi $query $pkgnum $cust_pkg $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(eidiot popurl);
use FS::Record qw(qsearchs);
+use FS::CGI qw(popurl eidiot);
use FS::cust_pkg;
-use FS::CGI qw(idiot);
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
#untaint pkgnum
-$QUERY_STRING =~ /^(\d+)$/ || die "Illegal pkgnum";
-my($pkgnum)=$1;
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal pkgnum";
+$pkgnum = $1;
-my($cust_pkg) = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+$cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
-bless($cust_pkg,'FS::cust_pkg');
-my($error)=$cust_pkg->cancel;
-idiot($error) if $error;
+$error = $cust_pkg->cancel;
+eidiot($error) if $error;
-$cgi->redirect("../view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
diff --git a/htdocs/misc/delete-customer.cgi b/htdocs/misc/delete-customer.cgi
new file mode 100755
index 000000000..8addbd657
--- /dev/null
+++ b/htdocs/misc/delete-customer.cgi
@@ -0,0 +1,58 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: delete-customer.cgi,v 1.1 1999-04-15 16:44:36 ivan Exp $
+#
+# $Log: delete-customer.cgi,v $
+# Revision 1.1 1999-04-15 16:44:36 ivan
+# delete customers
+#
+
+use strict;
+use vars qw( $cgi $conf $query $custnum $new_custnum $cust_main );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(header popurl);
+use FS::Record qw(qsearch qsearchs);
+use FS::cust_main;
+
+$cgi = new CGI;
+cgisuidsetup($cgi);
+
+$conf = new FS::Conf;
+die "Customer deletions not enabled" unless $conf->exists('deletecustomers');
+
+if ( $cgi->param('error') ) {
+ $custnum = $cgi->param('custnum');
+ $new_custnum = $cgi->param('new_custnum');
+} else {
+ ($query) = $cgi->keywords;
+ $query =~ /^(\d+)$/ or die "Illegal query: $query";
+ $custnum = $1;
+ $new_custnum = '';
+}
+$cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } )
+ or die "Customer not found: $custnum";
+
+print $cgi->header ( '-expires' => 'now' ), header('Delete customer');
+
+print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
+ "</FONT>"
+ if $cgi->param('error');
+
+print
+ qq!<form action="!, popurl(1), qq!process/delete-customer.cgi" method=post>!,
+ qq!<input type="hidden" name="custnum" value="$custnum">!;
+
+if ( qsearch('cust_pkg', { 'custnum' => $custnum, 'cancel' => '' } ) ) {
+ print "Move uncancelled packages to customer number ",
+ qq!<input type="text" name="new_custnum" value="$new_custnum"><br><br>!;
+}
+
+print <<END;
+This will <b>completely remove</b> all traces of this customer record.
+<br>Are you <b>absolutely sure</b> you want to delete this customer?
+<br><input type="submit" value="Yes">
+</form></body></html>
+END
+
diff --git a/htdocs/misc/expire_pkg.cgi b/htdocs/misc/expire_pkg.cgi
index 163516627..cf1f23153 100755
--- a/htdocs/misc/expire_pkg.cgi
+++ b/htdocs/misc/expire_pkg.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# expire_pkg.cgi: Expire a package
+# $Id: expire_pkg.cgi,v 1.4 1999-02-28 00:03:50 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/expire_pkg.cgi
#
-# Note: Should be run setuid freeside as user nobody
-#
# based on susp_pkg
# ivan@voicenet.com 97-jul-29
#
@@ -14,58 +12,50 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: expire_pkg.cgi,v $
+# Revision 1.4 1999-02-28 00:03:50 ivan
+# removed misleading comments
+#
+# Revision 1.3 1999/01/19 05:14:05 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.2 1998/12/17 09:12:44 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
+use vars qw ( $cgi $date $pkgnum $cust_pkg %hash $new $error );
use Date::Parse;
-use CGI::Request;
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl eidiot);
use FS::Record qw(qsearchs);
use FS::cust_pkg;
-my($req) = new CGI::Request;
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
#untaint date & pkgnum
-my($date);
-if ( $req->param('date') ) {
- str2time($req->param('date')) =~ /^(\d+)$/ or die "Illegal date";
+if ( $cgi->param('date') ) {
+ str2time($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date";
$date=$1;
} else {
$date='';
}
-$req->param('pkgnum') =~ /^(\d+)$/ or die "Illegal pkgnum";
-my($pkgnum)=$1;
+$cgi->param('pkgnum') =~ /^(\d+)$/ or die "Illegal pkgnum";
+$pkgnum = $1;
-my($cust_pkg) = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
-my(%hash)=$cust_pkg->hash;
+$cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+%hash = $cust_pkg->hash;
$hash{expire}=$date;
-my($new)=create FS::cust_pkg ( \%hash );
-my($error) = $new->replace($cust_pkg);
-&idiot($error) if $error;
-
-$req->cgi->redirect("../view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+$new = new FS::cust_pkg ( \%hash );
+$error = $new->replace($cust_pkg);
+&eidiot($error) if $error;
-sub idiot {
- my($error)=@_;
- SendHeaders();
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error expiring package</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Error expiring package</H1>
- </CENTER>
- <HR>
- There has been an error expiring this package: $error
- </BODY>
- </HEAD>
-</HTML>
-END
- exit;
-}
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
diff --git a/htdocs/misc/link.cgi b/htdocs/misc/link.cgi
index d1db000ec..eb1780711 100755
--- a/htdocs/misc/link.cgi
+++ b/htdocs/misc/link.cgi
@@ -1,21 +1,45 @@
#!/usr/bin/perl -Tw
#
-# link: instead of adding a new account, link to an existing. (output form)
-#
-# Note: Should be run setuid freeside as user nobody
+# $Id: link.cgi,v 1.7 1999-04-08 11:31:40 ivan Exp $
#
# ivan@voicenet.com 97-feb-5
#
# rewrite ivan@sisd.com 98-mar-17
#
# can also link on some other fields now (about time) ivan@sisd.com 98-jun-24
+#
+# $Log: link.cgi,v $
+# Revision 1.7 1999-04-08 11:31:40 ivan
+# *** empty log message ***
+#
+# Revision 1.6 1999/02/28 00:03:51 ivan
+# removed misleading comments
+#
+# Revision 1.5 1999/01/19 05:14:06 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:36 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/23 03:03:39 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:12:45 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw ( %link_field $cgi $pkgnum $svcpart $query $part_svc $svc $svcdb
+ $link_field );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl header);
use FS::Record qw(qsearchs);
-my(%link_field)=(
+%link_field = (
'svc_acct' => 'username',
'svc_domain' => 'domain',
'svc_acct_sm' => '',
@@ -23,33 +47,22 @@ my(%link_field)=(
'svc_wo' => '',
);
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
cgisuidsetup($cgi);
-my($pkgnum,$svcpart);
-foreach $_ (split(/-/,$QUERY_STRING)) { #get & untaint pkgnum & svcpart
+($query) = $cgi->keywords;
+foreach $_ (split(/-/,$query)) { #get & untaint pkgnum & svcpart
$pkgnum=$1 if /^pkgnum(\d+)$/;
$svcpart=$1 if /^svcpart(\d+)$/;
}
-my($part_svc) = qsearchs('part_svc',{'svcpart'=>$svcpart});
-my($svc) = $part_svc->getfield('svc');
-my($svcdb) = $part_svc->getfield('svcdb');
-my($link_field) = $link_field{$svcdb};
+$part_svc = qsearchs('part_svc',{'svcpart'=>$svcpart});
+$svc = $part_svc->getfield('svc');
+$svcdb = $part_svc->getfield('svcdb');
+$link_field = $link_field{$svcdb};
-CGI::Base::SendHeaders();
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Link to existing $svc account</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Link to existing $svc account</H1>
- </CENTER><HR>
- <FORM ACTION="process/link.cgi" METHOD=POST>
-END
+print $cgi->header( '-expires' => 'now' ), header("Link to existing $svc"),
+ qq!<FORM ACTION="!, popurl(1), qq!process/link.cgi" METHOD=POST>!;
if ( $link_field ) {
print <<END;
diff --git a/htdocs/misc/print-invoice.cgi b/htdocs/misc/print-invoice.cgi
index 084dcc1c4..213f15406 100755
--- a/htdocs/misc/print-invoice.cgi
+++ b/htdocs/misc/print-invoice.cgi
@@ -1,57 +1,51 @@
#!/usr/bin/perl -Tw
#
+# $Id: print-invoice.cgi,v 1.4 1999-01-19 05:14:07 ivan Exp $
+#
# just a kludge for now, since this duplicates in a way it shouldn't stuff from
# Bill.pm (like $lpr) ivan@sisd.com 98-jun-16
+#
+# $Log: print-invoice.cgi,v $
+# Revision 1.4 1999-01-19 05:14:07 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1998/12/23 03:04:24 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:12:47 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw($conf $cgi $lpr $query $invnum $cust_bill $custnum );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl);
use FS::Record qw(qsearchs);
-use FS::Invoice;
-
-my($lpr) = "|lpr -h";
+use FS::cust_bill;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
+$conf = new FS::Conf;
+$lpr = $conf->config('lpr');
+
#untaint invnum
-$QUERY_STRING =~ /^(\d*)$/;
-my($invnum)=$1;
-my($cust_bill)=qsearchs('cust_bill',{'invnum'=>$invnum});
+($query) = $cgi->keywords;
+$query =~ /^(\d*)$/;
+$invnum = $1;
+$cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
die "Can't find invoice!\n" unless $cust_bill;
- bless($cust_bill,"FS::Invoice");
- open(LPR,$lpr) or die "Can't open $lpr: $!";
+ open(LPR,"|$lpr") or die "Can't open $lpr: $!";
print LPR $cust_bill->print_text; #( date )
close LPR
or die $! ? "Error closing $lpr: $!"
: "Exit status $? from $lpr";
-my($custnum)=$cust_bill->getfield('custnum');
-
-$cgi->redirect("../view/cust_main.cgi?$custnum#history");
-
-sub idiot {
- my($error)=@_;
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error printing invoice</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error printing invoice</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- </BODY>
-</HTML>
-END
-
- exit;
-
-}
+$custnum = $cust_bill->getfield('custnum');
+
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?$custnum#history");
diff --git a/htdocs/misc/process/delete-customer.cgi b/htdocs/misc/process/delete-customer.cgi
new file mode 100755
index 000000000..0a939c559
--- /dev/null
+++ b/htdocs/misc/process/delete-customer.cgi
@@ -0,0 +1,46 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: delete-customer.cgi,v 1.1 1999-04-15 16:44:36 ivan Exp $
+#
+# $Log: delete-customer.cgi,v $
+# Revision 1.1 1999-04-15 16:44:36 ivan
+# delete customers
+#
+
+use strict;
+use vars qw ( $cgi $conf $custnum $new_custnum $cust_main $error );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use FS::UID qw(cgisuidsetup);
+use FS::Record qw(qsearchs);
+use FS::CGI qw(popurl);
+use FS::cust_main;
+
+$cgi = new CGI;
+cgisuidsetup($cgi);
+
+$conf = new FS::Conf;
+die "Customer deletions not enabled" unless $conf->exists('deletecustomers');
+
+$cgi->param('custnum') =~ /^(\d+)$/;
+$custnum = $1;
+if ( $cgi->param('new_custnum') ) {
+ $cgi->param('new_custnum') =~ /^(\d+)$/
+ or die "Illegal new customer number: ". $cgi->param('new_custnum');
+ $new_custnum = $1;
+} else {
+ $new_custnum = '';
+}
+$cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } )
+ or die "Customer not found: $custnum";
+
+$error = $cust_main->delete($new_custnum);
+
+if ( $error ) {
+ $cgi->param('error', $error);
+ print $cgi->redirect(popurl(2). "delete-customer.cgi?". $cgi->query_string );
+} elsif ( $new_custnum ) {
+ print $cgi->redirect(popurl(3). "view/cust_main.cgi?$new_custnum");
+} else {
+ print $cgi->redirect(popurl(3));
+}
diff --git a/htdocs/misc/process/link.cgi b/htdocs/misc/process/link.cgi
index 23fb05386..eec43cf47 100755
--- a/htdocs/misc/process/link.cgi
+++ b/htdocs/misc/process/link.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# process/link.cgi: link to existing customer (process form)
+# $Id: link.cgi,v 1.5 1999-04-15 14:09:17 ivan Exp $
#
# ivan@voicenet.com 97-feb-5
#
@@ -10,64 +10,64 @@
# bmccane@maxbaud.net 98-apr-3
#
# can also link on some other fields now (about time) ivan@sisd.com 98-jun-24
+#
+# $Log: link.cgi,v $
+# Revision 1.5 1999-04-15 14:09:17 ivan
+# get rid of top-level my() variables
+#
+# Revision 1.4 1999/02/07 09:59:35 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.3 1999/01/19 05:14:10 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.2 1998/12/17 09:15:00 ivan
+# s/CGI::Request/CGI.pm/;
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi $old $new $error $pkgnum $svcpart $svcnum );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
-use FS::CGI qw(idiot);
+use FS::CGI qw(popurl idiot);
use FS::UID qw(cgisuidsetup);
use FS::cust_svc;
use FS::Record qw(qsearchs);
-my($req)=new CGI::Request; # create form object
-cgisuidsetup($req->cgi);
-
-#$req->import_names('R'); #import CGI variables into package 'R';
+$cgi = new CGI;
+cgisuidsetup($cgi);
-$req->param('pkgnum') =~ /^(\d+)$/; my($pkgnum)=$1;
-$req->param('svcpart') =~ /^(\d+)$/; my($svcpart)=$1;
+$cgi->param('pkgnum') =~ /^(\d+)$/;
+$pkgnum = $1;
+$cgi->param('svcpart') =~ /^(\d+)$/;
+$svcpart = $1;
+$cgi->param('svcnum') =~ /^(\d*)$/;
+$svcnum = $1;
-$req->param('svcnum') =~ /^(\d*)$/; my($svcnum)=$1;
unless ( $svcnum ) {
my($part_svc) = qsearchs('part_svc',{'svcpart'=>$svcpart});
my($svcdb) = $part_svc->getfield('svcdb');
- $req->param('link_field') =~ /^(\w+)$/; my($link_field)=$1;
- my($svc_acct)=qsearchs($svcdb,{$link_field => $req->param('link_value') });
- idiot("$link_field not found!") unless $svc_acct;
+ $cgi->param('link_field') =~ /^(\w+)$/; my($link_field)=$1;
+ my($svc_acct)=qsearchs($svcdb,{$link_field => $cgi->param('link_value') });
+ eidiot("$link_field not found!") unless $svc_acct;
$svcnum=$svc_acct->svcnum;
}
-my($old)=qsearchs('cust_svc',{'svcnum'=>$svcnum});
+$old = qsearchs('cust_svc',{'svcnum'=>$svcnum});
die "svcnum not found!" unless $old;
-my($new)=create FS::cust_svc ({
+$new = new FS::cust_svc ({
'svcnum' => $svcnum,
'pkgnum' => $pkgnum,
'svcpart' => $svcpart,
});
-my($error);
$error = $new->replace($old);
unless ($error) {
#no errors, so let's view this customer.
- $req->cgi->redirect("../../view/cust_pkg.cgi?$pkgnum");
+ print $cgi->redirect(popurl(3). "view/cust_pkg.cgi?$pkgnum");
} else {
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Error</H4>
- </CENTER>
- Your update did not occur because of the following error:
- <P><B>$error</B>
- <P>Hit the <I>Back</I> button in your web browser, correct this mistake, and submit the form again.
- </BODY>
-</HTML>
-END
-
+ idiot($error);
}
diff --git a/htdocs/misc/susp_pkg.cgi b/htdocs/misc/susp_pkg.cgi
index 7b23caeb2..abe4f70b0 100755
--- a/htdocs/misc/susp_pkg.cgi
+++ b/htdocs/misc/susp_pkg.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# susp_pkg.cgi: Suspend a package
+# $Id: susp_pkg.cgi,v 1.6 1999-04-08 10:35:02 ivan Exp $
#
# Usage: susp_pkg.cgi pkgnum
# http://server.name/path/susp_pkg.cgi pkgnum
#
-# Note: Should be run setuid freeside as user nobody
-#
# probably should generalize this to do cancels, suspensions, unsuspensions, etc.
#
# ivan@voicenet.com 97-feb-27
@@ -21,48 +19,46 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: susp_pkg.cgi,v $
+# Revision 1.6 1999-04-08 10:35:02 ivan
+# import necessary subroutines from FS::CGI
+#
+# Revision 1.5 1999/02/28 00:03:52 ivan
+# removed misleading comments
+#
+# Revision 1.4 1999/01/19 05:14:08 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1998/12/23 03:04:56 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:12:48 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use vars qw( $cgi $query $pkgnum $cust_pkg $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearchs);
+use FS::CGI qw(popurl eidiot);
use FS::cust_pkg;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
#untaint pkgnum
-$QUERY_STRING =~ /^(\d+)$/ || die "Illegal pkgnum";
-my($pkgnum)=$1;
-
-my($cust_pkg) = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal pkgnum";
+$pkgnum = $1;
-bless($cust_pkg,'FS::cust_pkg');
-my($error)=$cust_pkg->suspend;
-&idiot($error) if $error;
+$cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
-$cgi->redirect("../view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+$error = $cust_pkg->suspend;
+&eidiot($error) if $error;
-sub idiot {
- my($error)=@_;
- SendHeaders();
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error suspending package</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Error suspending package</H1>
- </CENTER>
- <HR>
- There has been an error suspending this package: $error
- </BODY>
- </HEAD>
-</HTML>
-END
- exit;
-}
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
diff --git a/htdocs/misc/unsusp_pkg.cgi b/htdocs/misc/unsusp_pkg.cgi
index 2f340c6fa..9e60064c3 100755
--- a/htdocs/misc/unsusp_pkg.cgi
+++ b/htdocs/misc/unsusp_pkg.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# susp_pkg.cgi: Unsuspend a package
+# $Id: unsusp_pkg.cgi,v 1.5 1999-02-28 00:03:53 ivan Exp $
#
# Usage: susp_pkg.cgi pkgnum
# http://server.name/path/susp_pkg.cgi pkgnum
#
-# Note: Should be run setuid freeside as user nobody
-#
# probably should generalize this to do cancels, suspensions, unsuspensions, etc.
#
# ivan@voicenet.com 97-feb-27
@@ -21,48 +19,43 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: unsusp_pkg.cgi,v $
+# Revision 1.5 1999-02-28 00:03:53 ivan
+# removed misleading comments
+#
+# Revision 1.4 1999/01/19 05:14:09 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1998/12/23 03:05:25 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:12:49 ivan
+# s/CGI::(Request|Base)/CGI.pm/;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use vars qw( $cgi $query $pkgnum $cust_pkg $error );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl eidiot);
use FS::Record qw(qsearchs);
use FS::cust_pkg;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
#untaint pkgnum
-$QUERY_STRING =~ /^(\d+)$/ || die "Illegal pkgnum";
-my($pkgnum)=$1;
-
-my($cust_pkg) = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal pkgnum";
+$pkgnum = $1;
-bless($cust_pkg,'FS::cust_pkg');
-my($error)=$cust_pkg->unsuspend;
-&idiot($error) if $error;
+$cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
-$cgi->redirect("../view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
+$error = $cust_pkg->unsuspend;
+&eidiot($error) if $error;
-sub idiot {
- my($error)=@_;
- SendHeaders();
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Error unsuspending package</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Error unsuspending package</H1>
- </CENTER>
- <HR>
- There has been an error unsuspending this package: $error
- </BODY>
- </HEAD>
-</HTML>
-END
- exit;
-}
+print $cgi->redirect(popurl(2). "view/cust_main.cgi?".$cust_pkg->getfield('custnum'));
diff --git a/htdocs/search/cust_bill.cgi b/htdocs/search/cust_bill.cgi
index 5be84b79e..c849341e3 100755
--- a/htdocs/search/cust_bill.cgi
+++ b/htdocs/search/cust_bill.cgi
@@ -1,46 +1,44 @@
#!/usr/bin/perl -Tw
#
-# cust_bill.cgi: Search for invoices (process form)
+# $Id: cust_bill.cgi,v 1.4 1999-02-28 00:03:54 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/cust_bill.cgi
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 97-apr-4
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: cust_bill.cgi,v $
+# Revision 1.4 1999-02-28 00:03:54 ivan
+# removed misleading comments
+#
+# Revision 1.3 1999/01/19 05:14:11 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.2 1998/12/17 09:41:07 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi $invnum );
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl idiot);
use FS::Record qw(qsearchs);
-my($req)=new CGI::Request;
-cgisuidsetup($req->cgi);
+$cgi = new CGI;
+cgisuidsetup($cgi);
-$req->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/;
-my($invnum)=$2;
+$cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/;
+$invnum = $2;
if ( qsearchs('cust_bill',{'invnum'=>$invnum}) ) {
- $req->cgi->redirect("../view/cust_bill.cgi?$invnum"); #redirect
+ print $cgi->redirect(popurl(2). "view/cust_bill.cgi?$invnum"); #redirect
} else { #error
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Invoice Search Error</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H3>Invoice Search Error</H3>
- <HR>
- Invoice not found.
- </CENTER>
- </BODY>
-</HTML>
-END
-
+ idiot("Invoice not found.");
}
diff --git a/htdocs/search/cust_main-payinfo.html b/htdocs/search/cust_main-payinfo.html
index 92341ad13..47bb83cbd 100755
--- a/htdocs/search/cust_main-payinfo.html
+++ b/htdocs/search/cust_main-payinfo.html
@@ -2,11 +2,11 @@
<HEAD>
<TITLE>Customer Search</TITLE>
</HEAD>
- <BODY>
- <CENTER>
- <H1>Customer Search</H1>
- </CENTER>
- <HR>
+ <BODY BGCOLOR="#ffffff">
+ <FONT COLOR="#ff0000" SIZE=7>
+ Customer Search
+ </FONT>
+ <BR>
<FORM ACTION="cust_main.cgi" METHOD="post">
Search for <B>Credit card #</B>:
<INPUT TYPE="hidden" NAME="card_on" VALUE="TRUE">
@@ -15,7 +15,6 @@
<P><INPUT TYPE="submit" VALUE="Search">
</FORM>
- <HR>
</BODY>
</HTML>
diff --git a/htdocs/search/cust_main.cgi b/htdocs/search/cust_main.cgi
index 70ce991f7..ef076f97e 100755
--- a/htdocs/search/cust_main.cgi
+++ b/htdocs/search/cust_main.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# process/cust_main.cgi: Search for customers (process form)
+# $Id: cust_main.cgi,v 1.14 1999-08-12 04:45:21 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/cust_main.cgi
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 96-dec-12
#
# rewrite ivan@sisd.com 98-mar-4
@@ -17,64 +15,119 @@
# bmccane@maxbaud.net 98-apr-3
#
# display total, use FS::CGI ivan@sisd.com 98-jul-17
+#
+# $Log: cust_main.cgi,v $
+# Revision 1.14 1999-08-12 04:45:21 ivan
+# typo - missed a paren
+#
+# Revision 1.13 1999/08/12 04:32:21 ivan
+# hidecancelledcustomers
+#
+# Revision 1.12 1999/07/17 10:38:52 ivan
+# scott nelson <scott@ultimanet.com> noticed this mod_perl-triggered bug and
+# gave me a great bugreport at the last rhythmethod
+#
+# Revision 1.11 1999/04/09 04:22:34 ivan
+# also table()
+#
+# Revision 1.10 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.9 1999/02/28 00:03:55 ivan
+# removed misleading comments
+#
+# Revision 1.8 1999/02/07 09:59:36 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.7 1999/01/25 12:19:11 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.6 1999/01/19 05:14:12 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:37 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1998/12/30 00:57:50 ivan
+# bug
+#
+# Revision 1.3 1998/12/17 09:41:08 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
+# Revision 1.2 1998/11/12 08:10:22 ivan
+# CGI.pm instead of CGI-modules
+# relative URLs using popurl
+# got rid of lots of little tables
+# s/agrep/String::Approx/;
+# bubble up packages and services and link (slow)
+#
use strict;
-use CGI::Request;
+#use vars qw( $conf %ncancelled_pkgs %all_pkgs $cgi @cust_main $sortby );
+use vars qw( $conf %all_pkgs $cgi @cust_main $sortby );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use IO::Handle;
-use IPC::Open2;
+use String::Approx qw(amatch);
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header idiot);
-
-my($fuzziness)=2; #fuzziness for fuzzy searches, see man agrep
- #0-4: 0=no fuzz, 4=very fuzzy (too much fuzz!)
-
-my($req)=new CGI::Request;
-&cgisuidsetup($req->cgi);
-
-my(@cust_main);
-my($sortby);
+use FS::CGI qw(header menubar eidiot popurl table);
+use FS::cust_main;
+
+$cgi = new CGI;
+cgisuidsetup($cgi);
+
+$conf = new FS::Conf;
+
+if ( $cgi->keywords ) {
+ my($query)=$cgi->keywords;
+ if ( $query eq 'custnum' ) {
+ $sortby=\*custnum_sort;
+ @cust_main=qsearch('cust_main',{});
+ } elsif ( $query eq 'last' ) {
+ $sortby=\*last_sort;
+ @cust_main=qsearch('cust_main',{});
+ } elsif ( $query eq 'company' ) {
+ $sortby=\*company_sort;
+ @cust_main=qsearch('cust_main',{});
+ }
+} else {
+ @cust_main=();
+ &cardsearch if ( $cgi->param('card_on') && $cgi->param('card') );
+ &lastsearch if ( $cgi->param('last_on') && $cgi->param('last_text') );
+ &companysearch if ( $cgi->param('company_on') && $cgi->param('company_text') );
+}
-my($query)=$req->cgi->var('QUERY_STRING');
-if ( $query eq 'custnum' ) {
- $sortby=\*custnum_sort;
- @cust_main=qsearch('cust_main',{});
-} elsif ( $query eq 'last' ) {
- $sortby=\*last_sort;
- @cust_main=qsearch('cust_main',{});
-} elsif ( $query eq 'company' ) {
- $sortby=\*company_sort;
- @cust_main=qsearch('cust_main',{});
+@cust_main = grep { $_->ncancelled_pkgs || ! $_->all_pkgs } @cust_main
+ if $conf->exists('hidecancelledcustomers');
+if ( $conf->exists('hidecancelledpackages' ) ) {
+ %all_pkgs = map { $_->custnum => [ $_->ncancelled_pkgs ] } @cust_main;
} else {
- &cardsearch if ($req->param('card_on') );
- &lastsearch if ($req->param('last_on') );
- &companysearch if ($req->param('company_on') );
+ %all_pkgs = map { $_->custnum => [ $_->all_pkgs ] } @cust_main;
}
if ( scalar(@cust_main) == 1 ) {
- $req->cgi->redirect("../view/cust_main.cgi?". $cust_main[0]->custnum);
+ print $cgi->redirect(popurl(2). "view/cust_main.cgi?". $cust_main[0]->custnum);
exit;
} elsif ( scalar(@cust_main) == 0 ) {
- idiot "No matching customers found!\n";
- exit;
+ eidiot "No matching customers found!\n";
} else {
my($total)=scalar(@cust_main);
- CGI::Base::SendHeaders(); # one guess
- print header("Customer Search Results",''), <<END;
-
- $total matching customers found
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
+ print $cgi->header( '-expires' => 'now' ), header("Customer Search Results",menubar(
+ 'Main Menu', popurl(2)
+ )), "$total matching customers found<BR>", &table(), <<END;
<TR>
- <TH>Cust. #</TH>
+ <TH></TH>
<TH>Contact name</TH>
<TH>Company</TH>
+ <TH>Packages</TH>
+ <TH COLSPAN=2>Services</TH>
</TR>
END
- my($lines)=16;
- my($lcount)=$lines;
my(%saw,$cust_main);
foreach $cust_main (
sort $sortby grep(!$saw{$_->custnum}++, @cust_main)
@@ -85,30 +138,52 @@ END
$cust_main->getfield('first'),
$cust_main->company,
);
+
+ my(@lol_cust_svc);
+ my($rowspan)=0;#scalar( @{$all_pkgs{$custnum}} );
+ foreach ( @{$all_pkgs{$custnum}} ) {
+ my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
+ push @lol_cust_svc, \@cust_svc;
+ $rowspan += scalar(@cust_svc) || 1;
+ }
+
+ #my($rowspan) = scalar(@{$all_pkgs{$custnum}});
+ my($view) = popurl(2). "view/cust_main.cgi?$custnum";
print <<END;
<TR>
- <TD><A HREF="../view/cust_main.cgi?$custnum"><FONT SIZE=-1>$custnum</FONT></A></TD>
- <TD><FONT SIZE=-1>$last, $first</FONT></TD>
- <TD><FONT SIZE=-1>$company</FONT></TD>
- </TR>
-END
- if ($lcount-- == 0) { # lots of little tables instead of one big one
- $lcount=$lines;
- print <<END;
- </TABLE>
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
- <TR>
- <TH>Cust. #</TH>
- <TH>Contact name</TH>
- <TH>Company<TH>
- </TR>
+ <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$custnum</FONT></A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$last, $first</FONT></A></TD>
+ <TD ROWSPAN=$rowspan><A HREF="$view"><FONT SIZE=-1>$company</FONT></A></TD>
END
+
+ my($n1)='';
+ foreach ( @{$all_pkgs{$custnum}} ) {
+ my($pkgnum) = ($_->pkgnum);
+ my($pkg) = $_->part_pkg->pkg;
+ my $comment = $_->part_pkg->comment;
+ my($pkgview) = popurl(2). "/view/cust_pkg.cgi?$pkgnum";
+ #my(@cust_svc) = shift @lol_cust_svc;
+ my(@cust_svc) = qsearch( 'cust_svc', { 'pkgnum' => $_->pkgnum } );
+ my($rowspan) = scalar(@cust_svc) || 1;
+
+ print $n1, qq!<TD ROWSPAN=$rowspan><A HREF="$pkgview"><FONT SIZE=-1>$pkg - $comment</FONT></A></TD>!;
+ my($n2)='';
+ foreach my $cust_svc ( @cust_svc ) {
+ my($label, $value, $svcdb) = $cust_svc->label;
+ my($svcnum) = $cust_svc->svcnum;
+ my($sview) = popurl(2). "/view";
+ print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
+ qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
+ $n2="</TR><TR>";
+ }
+ #print qq!</TR><TR>\n!;
+ $n1="</TR><TR>";
}
+ print "<\TR>";
}
print <<END;
</TABLE>
- </CENTER>
</BODY>
</HTML>
END
@@ -122,6 +197,8 @@ sub last_sort {
}
sub company_sort {
+ return -1 if $a->company && ! $b->company;
+ return 1 if ! $a->company && $b->company;
$a->getfield('company') cmp $b->getfield('company');
}
@@ -131,9 +208,9 @@ sub custnum_sort {
sub cardsearch {
- my($card)=$req->param('card');
+ my($card)=$cgi->param('card');
$card =~ s/\D//g;
- $card =~ /^(\d{13,16})$/ or do { idiot "Illegal card number\n"; exit; };
+ $card =~ /^(\d{13,16})$/ or eidiot "Illegal card number\n";
my($payinfo)=$1;
push @cust_main, qsearch('cust_main',{'payinfo'=>$payinfo, 'payby'=>'CARD'});
@@ -142,12 +219,12 @@ sub cardsearch {
sub lastsearch {
my(%last_type);
- foreach ( $req->param('last_type') ) {
+ foreach ( $cgi->param('last_type') ) {
$last_type{$_}++;
}
- $req->param('last_text') =~ /^([\w \,\.\-\']*)$/
- or do { idiot "Illegal last name"; exit; };
+ $cgi->param('last_text') =~ /^([\w \,\.\-\']*)$/
+ or eidiot "Illegal last name";
my($last)=$1;
if ( $last_type{'Exact'}
@@ -163,16 +240,9 @@ sub lastsearch {
my(@all_last)=map $_->getfield('last'), qsearch('cust_main',{});
if ($last_type{'Fuzzy'}) {
- my($reader,$writer) = ( new IO::Handle, new IO::Handle );
- open2($reader,$writer,'agrep',"-$fuzziness",'-i','-k',
- substr($last,0,30));
- print $writer join("\n",@all_last),"\n";
- close $writer;
- while (<$reader>) {
- chop;
- $last{$_}++;
- }
- close $reader;
+ foreach ( amatch($last, [ qw(i) ], @all_last) ) {
+ $last{$_}++;
+ }
}
#if ($last_type{'Sound-alike'}) {
@@ -189,12 +259,12 @@ sub lastsearch {
sub companysearch {
my(%company_type);
- foreach ( $req->param('company_type') ) {
+ foreach ( $cgi->param('company_type') ) {
$company_type{$_}++
};
- $req->param('company_text') =~ /^([\w \,\.\-\']*)$/
- or do { idiot "Illegal company"; exit; };
+ $cgi->param('company_text') =~ /^([\w \,\.\-\']*)$/
+ or eidiot "Illegal company";
my($company)=$1;
if ( $company_type{'Exact'}
@@ -210,16 +280,9 @@ sub companysearch {
my(@all_company)=map $_->company, qsearch('cust_main',{});
if ($company_type{'Fuzzy'}) {
- my($reader,$writer) = ( new IO::Handle, new IO::Handle );
- open2($reader,$writer,'agrep',"-$fuzziness",'-i','-k',
- substr($company,0,30));
- print $writer join("\n",@all_company),"\n";
- close $writer;
- while (<$reader>) {
- chop;
+ foreach ( amatch($company, [ qw(i) ], @all_company ) ) {
$company{$_}++;
}
- close $reader;
}
#if ($company_type{'Sound-alike'}) {
diff --git a/htdocs/search/cust_main.html b/htdocs/search/cust_main.html
index 656943f9c..3184698b4 100755
--- a/htdocs/search/cust_main.html
+++ b/htdocs/search/cust_main.html
@@ -2,22 +2,22 @@
<HEAD>
<TITLE>Customer Search</TITLE>
</HEAD>
- <BODY>
- <CENTER>
- <H1>Customer Search</H1>
- </CENTER>
- <HR>
+ <BODY BGCOLOR="#ffffff">
+ <FONT COLOR="#ff0000" SIZE=7>
+ Customer Search
+ </FONT>
+ <BR>
<FORM ACTION="cust_main.cgi" METHOD="post">
- <INPUT TYPE="checkbox" NAME="last_on"> Search for <B>last name</B>:
+ <INPUT TYPE="checkbox" NAME="last_on" CHECKED> Search for <B>last name</B>:
<INPUT TYPE="text" NAME="last_text">
- using search method(s): <SELECT NAME="last_type" MULTIPLE>
+ using search method: <SELECT NAME="last_type">
<OPTION SELECTED>Fuzzy
<OPTION>Exact
</SELECT>
- <P><INPUT TYPE="checkbox" NAME="company_on"> Search for <B>company</B>:
+ <P><INPUT TYPE="checkbox" NAME="company_on" CHECKED> Search for <B>company</B>:
<INPUT TYPE="text" NAME="company_text">
- using search methods(s): <SELECT NAME="company_type" MULTIPLE>
+ using search methods: <SELECT NAME="company_type">
<OPTION SELECTED>Fuzzy
<OPTION>Exact
</SELECT>
diff --git a/htdocs/search/cust_pkg.cgi b/htdocs/search/cust_pkg.cgi
index 967068f5e..033bc2585 100755
--- a/htdocs/search/cust_pkg.cgi
+++ b/htdocs/search/cust_pkg.cgi
@@ -1,29 +1,61 @@
#!/usr/bin/perl -Tw
#
-# cust_pkg.cgi: search/browse for packages
+# $Id: cust_pkg.cgi,v 1.9 1999-07-17 10:38:52 ivan Exp $
#
# based on search/svc_acct.cgi ivan@sisd.com 98-jul-17
+#
+# $Log: cust_pkg.cgi,v $
+# Revision 1.9 1999-07-17 10:38:52 ivan
+# scott nelson <scott@ultimanet.com> noticed this mod_perl-triggered bug and
+# gave me a great bugreport at the last rhythmethod
+#
+# Revision 1.8 1999/02/09 09:22:57 ivan
+# visual and bugfixes
+#
+# Revision 1.7 1999/02/07 09:59:37 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.6 1999/01/19 05:14:13 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:38 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1999/01/18 09:22:33 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.3 1998/12/23 03:05:59 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:41:09 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi @cust_pkg $sortby $query );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header idiot);
-
-my($req)=new CGI::Request;
-&cgisuidsetup($req->cgi);
+use FS::CGI qw(header eidiot popurl);
+use FS::cust_pkg;
+use FS::pkg_svc;
+use FS::cust_svc;
+use FS::cust_main;
-my(@cust_pkg,$sortby);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-my($query)=$req->cgi->var('QUERY_STRING');
+($query) = $cgi->keywords;
#this tree is a little bit redundant
if ( $query eq 'pkgnum' ) {
$sortby=\*pkgnum_sort;
@cust_pkg=qsearch('cust_pkg',{});
} elsif ( $query eq 'APKG_pkgnum' ) {
$sortby=\*pkgnum_sort;
-
+ @cust_pkg=();
#perhaps this should go in cust_pkg as a qsearch-like constructor?
my($cust_pkg);
foreach $cust_pkg (qsearch('cust_pkg',{})) {
@@ -50,27 +82,23 @@ if ( $query eq 'pkgnum' ) {
if ( scalar(@cust_pkg) == 1 ) {
my($pkgnum)=$cust_pkg[0]->pkgnum;
- $req->cgi->redirect("../view/cust_pkg.cgi?$pkgnum");
+ print $cgi->redirect(popurl(2). "view/cust_pkg.cgi?$pkgnum");
exit;
} elsif ( scalar(@cust_pkg) == 0 ) { #error
- &idiot("No packages found");
- exit;
+ eidiot("No packages found");
} else {
my($total)=scalar(@cust_pkg);
- CGI::Base::SendHeaders(); # one guess
- print header('Package Search Results',''), <<END;
+ print $cgi->header( '-expires' => 'now' ), header('Package Search Results',''), <<END;
$total matching packages found
<TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
<TR>
<TH>Package #</TH>
<TH>Customer #</TH>
- <TH>Name</TH>
+ <TH>Contact name</TH>
<TH>Company</TH>
</TR>
END
- my($lines)=16;
- my($lcount)=$lines;
my(%saw,$cust_pkg);
foreach $cust_pkg (
sort $sortby grep(!$saw{$_->pkgnum}++, @cust_pkg)
@@ -82,33 +110,20 @@ END
$cust_main->last. ', '. $cust_main->first,
$cust_main->company,
);
+ my $p = popurl(2);
print <<END;
<TR>
- <TD><A HREF="../view/cust_pkg.cgi?$pkgnum"><FONT SIZE=-1>$pkgnum</FONT></A></TD>
- <TD><FONT SIZE=-1>$custnum</FONT></TD>
- <TD><FONT SIZE=-1>$name</FONT></TD>
- <TD><FONT SIZE=-1>$company</FONT></TD>
- </TR>
-END
- if ($lcount-- == 0) { # lots of little tables instead of one big one
- $lcount=$lines;
- print <<END;
- </TABLE>
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
- <TR>
- <TH>Package #</TH>
- <TH>Customer #</TH>
- <TH>Name</TH>
- <TH>Company</TH>
- <TH>
+ <TD><A HREF="${p}view/cust_pkg.cgi?$pkgnum"><FONT SIZE=-1>$pkgnum</FONT></A></TD>
+ <TD><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$custnum</A></FONT></TD>
+ <TD><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$name</A></FONT></TD>
+ <TD><FONT SIZE=-1><A HREF="${p}view/cust_main.cgi?$custnum">$company</A></FONT></TD>
</TR>
END
- }
+
}
print <<END;
</TABLE>
- </CENTER>
</BODY>
</HTML>
END
diff --git a/htdocs/search/svc_acct.cgi b/htdocs/search/svc_acct.cgi
index 250a741db..850865789 100755
--- a/htdocs/search/svc_acct.cgi
+++ b/htdocs/search/svc_acct.cgi
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# svc_acct.cgi: Search for customers (process form)
+# $Id: svc_acct.cgi,v 1.11 1999-04-14 11:25:33 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/svc_acct.cgi
@@ -21,20 +21,56 @@
# use FS::CGI, show total ivan@sisd.com 98-jul-17
#
# give service and customer info too ivan@sisd.com 98-aug-16
+#
+# $Log: svc_acct.cgi,v $
+# Revision 1.11 1999-04-14 11:25:33 ivan
+# *** empty log message ***
+#
+# Revision 1.10 1999/04/14 11:20:21 ivan
+# visual fix
+#
+# Revision 1.9 1999/04/10 01:53:18 ivan
+# oops, search usernames limited to 8 chars
+#
+# Revision 1.8 1999/04/09 23:43:29 ivan
+# just in case
+#
+# Revision 1.7 1999/02/07 09:59:38 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.6 1999/01/19 05:14:14 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:39 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1999/01/18 09:22:34 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.3 1998/12/23 03:06:28 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:41:10 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
use strict;
-use CGI::Request; # form processing module
+use vars qw( $cgi @svc_acct $sortby $query );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header idiot);
-
-my($req)=new CGI::Request; # create form object
-&cgisuidsetup($req->cgi);
+use FS::CGI qw(header eidiot popurl table);
+use FS::svc_acct;
+use FS::cust_main;
-my(@svc_acct,$sortby);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-my($query)=$req->cgi->var('QUERY_STRING');
+($query)=$cgi->keywords;
+$query ||= ''; #to avoid use of unitialized value errors
#this tree is a little bit redundant
if ( $query eq 'svcnum' ) {
$sortby=\*svcnum_sort;
@@ -64,36 +100,35 @@ if ( $query eq 'svcnum' ) {
'pkgnum' => '',
}), qsearch('svc_acct',{});
} else {
+ $sortby=\*uid_sort;
&usernamesearch;
}
if ( scalar(@svc_acct) == 1 ) {
my($svcnum)=$svc_acct[0]->svcnum;
- $req->cgi->redirect("../view/svc_acct.cgi?$svcnum"); #redirect
+ print $cgi->redirect(popurl(2). "view/svc_acct.cgi?$svcnum"); #redirect
exit;
} elsif ( scalar(@svc_acct) == 0 ) { #error
- idiot("Account not found");
- exit;
+ eidiot("Account not found");
} else {
my($total)=scalar(@svc_acct);
- CGI::Base::SendHeaders(); # one guess
- print header("Account Search Results",''), <<END;
- $total matching accounts found
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
+ print $cgi->header( '-expires' => 'now' ),
+ header("Account Search Results",''),
+ "$total matching accounts found",
+ &table(), <<END;
<TR>
- <TH>Service #</TH>
- <TH>Username</TH>
- <TH>UID</TH>
- <TH>Service</TH>
- <TH>Customer #</TH>
- <TH>Contact name</TH>
- <TH>Company</TH>
+ <TH><FONT SIZE=-1>Service #</FONT></TH>
+ <TH><FONT SIZE=-1>Username</FONT></TH>
+ <TH><FONT SIZE=-1>UID</FONT></TH>
+ <TH><FONT SIZE=-1>Service</FONT></TH>
+ <TH><FONT SIZE=-1>Customer #</FONT></TH>
+ <TH><FONT SIZE=-1>Contact name</FONT></TH>
+ <TH><FONT SIZE=-1>Company</FONT></TH>
</TR>
END
- my($lines)=16;
- my($lcount)=$lines;
my(%saw,$svc_acct);
+ my $p = popurl(2);
foreach $svc_acct (
sort $sortby grep(!$saw{$_->svcnum}++, @svc_acct)
) {
@@ -119,37 +154,23 @@ END
$cust_svc->pkgnum ? $cust_main->company : '',
);
my($pcustnum) = $custnum
- ? "<A HREF=\"../view/cust_main.cgi?$custnum\"><FONT SIZE=-1>$custnum</FONT></A>"
+ ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\"><FONT SIZE=-1>$custnum</FONT></A>"
: "<I>(unlinked)</I>"
;
- my($pname) = $custnum ? "$last, $first" : '';
+ my($pname) = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$last, $first</A>" : '';
+ my $pcompany = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$company</A>" : '';
print <<END;
<TR>
- <TD><A HREF="../view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$svcnum</FONT></A></TD>
- <TD><FONT SIZE=-1>$username</FONT></TD>
- <TD><FONT SIZE=-1>$uid</FONT></TD>
+ <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$svcnum</FONT></A></TD>
+ <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$username</FONT></A></TD>
+ <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$uid</FONT></A></TD>
<TD><FONT SIZE=-1>$svc</FONT></TH>
<TD><FONT SIZE=-1>$pcustnum</FONT></TH>
<TD><FONT SIZE=-1>$pname<FONT></TH>
- <TD><FONT SIZE=-1>$company</FONT></TH>
+ <TD><FONT SIZE=-1>$pcompany</FONT></TH>
</TR>
END
- if ($lcount-- == 0) { # lots of little tables instead of one big one
- $lcount=$lines;
- print <<END;
- </TABLE>
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
- <TR>
- <TH>Service #</TH>
- <TH>Userame</TH>
- <TH>UID</TH>
- <TH>Service</TH>
- <TH>Customer #</TH>
- <TH>Contact name</TH>
- <TH>Company</TH>
- </TR>
-END
- }
+
}
print <<END;
@@ -176,7 +197,7 @@ sub uid_sort {
sub usernamesearch {
- $req->param('username') =~ /^([\w\d\-]{2,8})$/; #untaint username_text
+ $cgi->param('username') =~ /^([\w\d\-]+)$/; #untaint username_text
my($username)=$1;
@svc_acct=qsearch('svc_acct',{'username'=>$username});
diff --git a/htdocs/search/svc_acct_sm.cgi b/htdocs/search/svc_acct_sm.cgi
index 3b1a4cf4e..ddf2a1f23 100755
--- a/htdocs/search/svc_acct_sm.cgi
+++ b/htdocs/search/svc_acct_sm.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# svc_acct_sm.cgi: Search for domains (process form)
+# $Id: svc_acct_sm.cgi,v 1.10 1999-07-20 06:03:36 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/svc_domain.cgi
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 96-mar-5
#
# need to look at table in results to make it more readable
@@ -17,33 +15,61 @@
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: svc_acct_sm.cgi,v $
+# Revision 1.10 1999-07-20 06:03:36 ivan
+# s/CGI::Request/CGI/; (how'd i miss that before?)
+#
+# Revision 1.9 1999/04/09 04:22:34 ivan
+# also table()
+#
+# Revision 1.8 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.7 1999/02/28 00:03:56 ivan
+# removed misleading comments
+#
+# Revision 1.6 1999/02/09 09:22:58 ivan
+# visual and bugfixes
+#
+# Revision 1.5 1999/01/19 05:14:16 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.4 1999/01/18 09:41:40 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.3 1998/12/17 09:41:11 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
use strict;
-use CGI::Request;
+use vars qw( $conf $cgi $mydomain $domuser $svc_domain $domsvc @svc_acct_sm );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl idiot header table);
use FS::Record qw(qsearch qsearchs);
+use FS::Conf;
+use FS::svc_domain;
+use FS::svc_acct_sm;
+use FS::svc_acct;
-my($conf_domain)="/var/spool/freeside/conf/domain";
-open(DOMAIN,$conf_domain) or die "Can't open $conf_domain: $!";
-my($mydomain)=map {
- /^(.*)$/ or die "Illegal line in $conf_domain!"; #yes, we trust the file
- $1
-} grep $_ !~ /^(#|$)/, <DOMAIN>;
-close DOMAIN;
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-my($req)=new CGI::Request; # create form object
-&cgisuidsetup($req->cgi);
+$conf = new FS::Conf;
+$mydomain = $conf->config('domain');
-$req->param('domuser') =~ /^([a-z0-9_\-]{0,32})$/;
-my($domuser)=$1;
+$cgi->param('domuser') =~ /^([a-z0-9_\-]{0,32})$/;
+$domuser = $1;
-$req->param('domain') =~ /^([\w\-\.]+)$/ or die "Illegal domain";
-my($svc_domain)=qsearchs('svc_domain',{'domain'=>$1})
+$cgi->param('domain') =~ /^([\w\-\.]+)$/ or die "Illegal domain";
+$svc_domain = qsearchs('svc_domain',{'domain'=>$1})
or die "Unknown domain";
-my($domsvc)=$svc_domain->svcnum;
+$domsvc = $svc_domain->svcnum;
-my(@svc_acct_sm);
if ($domuser) {
@svc_acct_sm=qsearch('svc_acct_sm',{
'domuser' => $domuser,
@@ -55,21 +81,14 @@ if ($domuser) {
if ( scalar(@svc_acct_sm) == 1 ) {
my($svcnum)=$svc_acct_sm[0]->svcnum;
- $req->cgi->redirect("../view/svc_acct_sm.cgi?$svcnum"); #redirect
+ print $cgi->redirect(popurl(2). "view/svc_acct_sm.cgi?$svcnum");
} elsif ( scalar(@svc_acct_sm) > 1 ) {
- CGI::Base::SendHeaders();
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Mail Alias Search Results</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H4>Mail Alias Search Results</H4>
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
+ print $cgi->header( '-expires' => 'now' ),
+ header('Mail Alias Search Results'),
+ &table(), <<END;
<TR>
- <TH>Mail to<BR><FONT SIZE=-2>(click here to view mail alias)</FONT></TH>
- <TH>Forwards to<BR><FONT SIZE=-2>(click here to view account)</FONT></TH>
+ <TH>Mail to<BR><FONT SIZE=-1>(click to view mail alias)</FONT></TH>
+ <TH>Forwards to<BR><FONT SIZE=-1>(click to view account)</FONT></TH>
</TR>
END
@@ -81,48 +100,41 @@ END
$svc_acct_sm->domuid,
$svc_acct_sm->domsvc,
);
- my($svc_domain)=qsearchs('svc_domain',{'svcnum'=>$domsvc});
- my($domain)=$svc_domain->domain;
- my($svc_acct)=qsearchs('svc_acct',{'uid'=>$domuid});
- my($username)=$svc_acct->username;
- my($svc_acct_svcnum)=$svc_acct->svcnum;
-
- print <<END;
-<TR>\n <TD> <A HREF="../view/svc_acct_sm.cgi?$svcnum">
-END
-
- print '', ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser );
- print <<END;
-\@$domain</A> </TD>\n
-<TD> <A HREF="../view/svc_acct.cgi?$svc_acct_svcnum">$username\@$mydomain</A> </TD>\n </TR>\n
-END
+ my $svc_domain = qsearchs( 'svc_domain', { 'svcnum' => $domsvc } );
+ if ( $svc_domain ) {
+ my $domain = $svc_domain->domain;
+
+ print qq!<TR><TD><A HREF="!. popurl(2). qq!view/svc_acct_sm.cgi?$svcnum">!,
+ #print '', ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser );
+ ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser ),
+ qq!\@$domain</A> </TD>!,
+ ;
+ } else {
+ my $warning = "couldn't find svc_domain.svcnum $svcnum ( svc_acct_sm.svcnum $svcnum";
+ warn $warning;
+ print "<TR><TD>WARNING: $warning</TD>";
+ }
+
+ my $svc_acct = qsearchs( 'svc_acct', { 'uid' => $domuid } );
+ if ( $svc_acct ) {
+ my $username = $svc_acct->username;
+ my $svc_acct_svcnum =$svc_acct->svcnum;
+ print qq!<TD><A HREF="!, popurl(2),
+ qq!view/svc_acct.cgi?$svc_acct_svcnum">$username\@$mydomain</A>!,
+ qq!</TD></TR>!
+ ;
+ } else {
+ my $warning = "couldn't find svc_acct.uid $domuid (svc_acct_sm.svcnum $svcnum)!";
+ warn $warning;
+ print "<TD>WARNING: $warning</TD></TR>";
+ }
}
- print <<END;
- </TABLE>
- </CENTER>
- </BODY>
-</HTML>
-END
+ print '</TABLE></BODY></HTML>';
} else { #error
- CGI::Base::SendHeaders(); # one guess
- print <<END;
-<HTML>
- <HEAD>
- <TITLE>Mail Alias Search Error</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H3>Mail Alias Search Error</H3>
- <HR>
- Mail Alias not found.
- </CENTER>
- </BODY>
-</HTML>
-END
-
+ idiot("Mail Alias not found");
}
diff --git a/htdocs/search/svc_domain.cgi b/htdocs/search/svc_domain.cgi
index d5277037b..bf85e4a73 100755
--- a/htdocs/search/svc_domain.cgi
+++ b/htdocs/search/svc_domain.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# svc_domain.cgi: Search for domains (process form)
+# $Id: svc_domain.cgi,v 1.10 1999-07-17 10:38:52 ivan Exp $
#
# Usage: post form to:
# http://server.name/path/svc_domain.cgi
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 97-mar-5
#
# rewrite ivan@sisd.com 98-mar-14
@@ -15,21 +13,57 @@
# bmccane@maxbaud.net 98-apr-3
#
# display total, use FS::CGI now does browsing too ivan@sisd.com 98-jul-17
+#
+# $Log: svc_domain.cgi,v $
+# Revision 1.10 1999-07-17 10:38:52 ivan
+# scott nelson <scott@ultimanet.com> noticed this mod_perl-triggered bug and
+# gave me a great bugreport at the last rhythmethod
+#
+# Revision 1.9 1999/04/15 13:39:16 ivan
+# $cgi->header( '-expires' => 'now' )
+#
+# Revision 1.8 1999/02/28 00:03:57 ivan
+# removed misleading comments
+#
+# Revision 1.7 1999/02/23 08:09:24 ivan
+# beginnings of one-screen new customer entry and some other miscellania
+#
+# Revision 1.6 1999/02/09 09:22:59 ivan
+# visual and bugfixes
+#
+# Revision 1.5 1999/02/07 09:59:39 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.4 1999/01/19 05:14:17 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.3 1998/12/23 03:06:50 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:41:12 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
use strict;
-use CGI::Request;
+use vars qw ( $cgi @svc_domain $sortby $query $conf $mydomain );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearch qsearchs);
-use FS::CGI qw(header idiot);
+use FS::CGI qw(header eidiot popurl);
+use FS::svc_domain;
+use FS::cust_svc;
+use FS::svc_acct_sm;
+use FS::svc_acct;
-my($req)=new CGI::Request;
-&cgisuidsetup($req->cgi);
+$cgi = new CGI;
+&cgisuidsetup($cgi);
-my(@svc_domain);
-my($sortby);
+$conf = new FS::Conf;
+$mydomain = $conf->config('domain');
-my($query)=$req->cgi->var('QUERY_STRING');
+($query)=$cgi->keywords;
if ( $query eq 'svcnum' ) {
$sortby=\*svcnum_sort;
@svc_domain=qsearch('svc_domain',{});
@@ -49,36 +83,35 @@ if ( $query eq 'svcnum' ) {
'pkgnum' => '',
}), qsearch('svc_domain',{});
} else {
- $req->param('domain') =~ /^([\w\-\.]+)$/;
+ $cgi->param('domain') =~ /^([\w\-\.]+)$/;
my($domain)=$1;
- push @svc_domain, qsearchs('svc_domain',{'domain'=>$domain});
+ #push @svc_domain, qsearchs('svc_domain',{'domain'=>$domain});
+ @svc_domain = qsearchs('svc_domain',{'domain'=>$domain});
}
if ( scalar(@svc_domain) == 1 ) {
- $req->cgi->redirect("../view/svc_domain.cgi?". $svc_domain[0]->svcnum);
+ print $cgi->redirect(popurl(2). "view/svc_domain.cgi?". $svc_domain[0]->svcnum);
exit;
} elsif ( scalar(@svc_domain) == 0 ) {
- idiot "No matching domains found!\n";
- exit;
+ eidiot "No matching domains found!\n";
} else {
- CGI::Base::SendHeaders(); # one guess
my($total)=scalar(@svc_domain);
- CGI::Base::SendHeaders(); # one guess
- print header("Domain Search Results",''), <<END;
+ print $cgi->header( '-expires' => 'now' ),
+ header("Domain Search Results",''), <<END;
$total matching domains found
<TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
<TR>
<TH>Service #</TH>
<TH>Domain</TH>
- <TH></TH>
+ <TH>Mail to<BR><FONT SIZE=-1>(click to view mail alias)</FONT></TH>
+ <TH>Forwards to<BR><FONT SIZE=-1>(click to view account)</FONT></TH>
</TR>
END
- my($lines)=16;
- my($lcount)=$lines;
my(%saw,$svc_domain);
+ my $p = popurl(2);
foreach $svc_domain (
sort $sortby grep(!$saw{$_->svcnum}++, @svc_domain)
) {
@@ -86,42 +119,76 @@ END
$svc_domain->svcnum,
$svc_domain->domain,
);
- my($malias);
- if ( qsearch('svc_acct_sm',{'domsvc'=>$svcnum}) ) {
- $malias=(
- qq|<FORM ACTION="svc_acct_sm.cgi" METHOD="post">|.
- qq|<INPUT TYPE="hidden" NAME="domuser" VALUE="">|.
- qq|<INPUT TYPE="hidden" NAME="domain" VALUE="$domain">|.
- qq|<INPUT TYPE="submit" VALUE="(mail aliases)">|.
- qq|</FORM>|
- );
- } else {
- $malias='';
- }
+ #my($malias);
+ #if ( qsearch('svc_acct_sm',{'domsvc'=>$svcnum}) ) {
+ # $malias=(
+ # qq|<FORM ACTION="svc_acct_sm.cgi" METHOD="post">|.
+ # qq|<INPUT TYPE="hidden" NAME="domuser" VALUE="">|.
+ # qq|<INPUT TYPE="hidden" NAME="domain" VALUE="$domain">|.
+ # qq|<INPUT TYPE="submit" VALUE="(mail aliases)">|.
+ # qq|</FORM>|
+ # );
+ #} else {
+ # $malias='';
+ #}
+
+ my @svc_acct_sm=qsearch('svc_acct_sm',{'domsvc' => $svcnum});
+ my $rowspan = scalar(@svc_acct_sm) || 1;
+
print <<END;
<TR>
- <TD><A HREF="../view/svc_domain.cgi?$svcnum"><FONT SIZE=-1>$svcnum</FONT></A></TD>
- <TD><FONT SIZE=-1>$domain</FONT></TD>
- <TD><FONT SIZE=-1>$malias</FONT></TD>
- </TR>
-END
- if ($lcount-- == 0) { # lots of little tables instead of one big one
- $lcount=$lines;
- print <<END;
- </TABLE>
- <TABLE BORDER=4 CELLSPACING=0 CELLPADDING=0>
- <TR>
- <TH>Service #</TH>
- <TH>Domain</TH>
- <TH></TH>
- </TR>
+ <TD ROWSPAN=$rowspan><A HREF="${p}view/svc_domain.cgi?$svcnum"><FONT SIZE=-1>$svcnum</FONT></A></TD>
+ <TD ROWSPAN=$rowspan>$domain</TD>
END
+
+ my $n1 = '';
+ # false laziness: this was stolen from search/svc_acct_sm.cgi. but the
+ # web interface in general needs to be rewritten in a mucho cleaner way
+ my($svc_acct_sm);
+ foreach $svc_acct_sm (@svc_acct_sm) {
+ my($svcnum,$domuser,$domuid,$domsvc)=(
+ $svc_acct_sm->svcnum,
+ $svc_acct_sm->domuser,
+ $svc_acct_sm->domuid,
+ $svc_acct_sm->domsvc,
+ );
+ #my $svc_domain = qsearchs( 'svc_domain', { 'svcnum' => $domsvc } );
+ #if ( $svc_domain ) {
+ # my $domain = $svc_domain->domain;
+
+ print qq!$n1<TD><A HREF="!. popurl(2). qq!view/svc_acct_sm.cgi?$svcnum">!,
+ #print '', ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser );
+ ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser ),
+ qq!\@$domain</A> </TD>!,
+ ;
+ #} else {
+ # my $warning = "couldn't find svc_domain.svcnum $svcnum ( svc_acct_sm.svcnum $svcnum";
+ # warn $warning;
+ # print "$n1<TD>WARNING: $warning</TD>";
+ #}
+
+ my $svc_acct = qsearchs( 'svc_acct', { 'uid' => $domuid } );
+ if ( $svc_acct ) {
+ my $username = $svc_acct->username;
+ my $svc_acct_svcnum =$svc_acct->svcnum;
+ print qq!<TD><A HREF="!, popurl(2),
+ qq!view/svc_acct.cgi?$svc_acct_svcnum">$username\@$mydomain</A>!,
+ qq!</TD></TR>!
+ ;
+ } else {
+ my $warning = "couldn't find svc_acct.uid $domuid (svc_acct_sm.svcnum $svcnum)!";
+ warn $warning;
+ print "<TD>WARNING: $warning</TD>";
+ }
+ $n1 = "</TR><TR>";
}
+ #end of false laziness
+ print "</TR>";
+
}
print <<END;
</TABLE>
- </CENTER>
</BODY>
</HTML>
END
diff --git a/htdocs/view/cust_bill.cgi b/htdocs/view/cust_bill.cgi
index 96101d004..93a6f7a29 100755
--- a/htdocs/view/cust_bill.cgi
+++ b/htdocs/view/cust_bill.cgi
@@ -1,9 +1,6 @@
#!/usr/bin/perl -Tw
#
-# Usage: cust_bill.cgi invnum
-# http://server.name/path/cust_bill.cgi?invnum
-#
-# Note: Should be run setuid freeside as user nobody.
+# $Id: cust_bill.cgi,v 1.8 1999-02-28 00:03:58 ivan Exp $
#
# this is a quick & ugly hack which does little more than add some formatting to the ascii output from /dbin/print-invoice
#
@@ -24,50 +21,67 @@
# bmccane@maxbaud.net 98-apr-3
#
# also print 'printed' field ivan@sisd.com 98-jul-10
+#
+# $Log: cust_bill.cgi,v $
+# Revision 1.8 1999-02-28 00:03:58 ivan
+# removed misleading comments
+#
+# Revision 1.7 1999/01/25 12:26:03 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.6 1999/01/19 05:14:18 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:42 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1998/12/30 23:03:33 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.3 1998/12/23 03:07:49 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.2 1998/12/17 09:57:20 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
use strict;
+use vars qw ( $cgi $query $invnum $cust_bill $custnum $printed $p );
use IO::File;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(header popurl menubar);
use FS::Record qw(qsearchs);
-use FS::Invoice;
+use FS::cust_bill;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
&cgisuidsetup($cgi);
#untaint invnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($invnum)=$1;
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+$invnum = $1;
-my($cust_bill) = qsearchs('cust_bill',{'invnum'=>$invnum});
+$cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
die "Invoice #$invnum not found!" unless $cust_bill;
-my($custnum) = $cust_bill->getfield('custnum');
+$custnum = $cust_bill->getfield('custnum');
-my($printed) = $cust_bill->printed;
+$printed = $cust_bill->printed;
-SendHeaders(); # one guess.
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Invoice View</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Invoice View</H1>
- <A HREF="../view/cust_main.cgi?$custnum">View this customer (#$custnum)</A> | <A HREF="../">Main menu</A>
- </CENTER><HR>
- <BASEFONT SIZE=3>
- <CENTER>
- <A HREF="../edit/cust_pay.cgi?$invnum">Enter payments (check/cash) against this invoice</A>
- <BR><A HREF="../misc/print-invoice.cgi?$invnum">Reprint this invoice</A>
+$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",
+)), <<END;
+ <A HREF="${p}edit/cust_pay.cgi?$invnum">Enter payments (check/cash) against this invoice</A>
+ <BR><A HREF="${p}misc/print-invoice.cgi?$invnum">Reprint this invoice</A>
<BR><BR>(Printed $printed times)
- </CENTER>
- <FONT SIZE=-1><PRE>
+ <PRE>
END
-bless($cust_bill,"FS::Invoice");
print $cust_bill->print_text;
#formatting
diff --git a/htdocs/view/cust_main.cgi b/htdocs/view/cust_main.cgi
index ca5fcd94f..055256570 100755
--- a/htdocs/view/cust_main.cgi
+++ b/htdocs/view/cust_main.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# cust_main.cgi: View a customer
+# $Id: cust_main.cgi,v 1.18 1999-08-12 04:16:01 ivan Exp $
#
# Usage: cust_main.cgi custnum
# http://server.name/path/cust_main.cgi?custnum
#
-# Note: Should be run setuid freeside as user nobody.
-#
# the payment history section could use some work, see below
#
# ivan@voicenet.com 96-nov-29 -> 96-dec-11
@@ -31,147 +29,229 @@
# bmccane@maxbaud.net 98-apr-3
#
# lose background, FS::CGI ivan@sisd.com 98-sep-2
+#
+# $Log: cust_main.cgi,v $
+# Revision 1.18 1999-08-12 04:16:01 ivan
+# hidecancelledpackages config option
+#
+# Revision 1.17 1999/04/15 16:44:36 ivan
+# delete customers
+#
+# Revision 1.16 1999/04/09 04:22:34 ivan
+# also table()
+#
+# Revision 1.15 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.14 1999/04/08 04:04:37 ivan
+# eliminate double // in links
+#
+# Revision 1.13 1999/02/28 00:04:00 ivan
+# removed misleading comments
+#
+# Revision 1.12 1999/02/07 09:59:40 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.11 1999/01/25 12:26:04 ivan
+# yet more mod_perl stuff
+#
+# Revision 1.10 1999/01/19 05:14:19 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.9 1999/01/18 09:41:43 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.8 1999/01/18 09:22:35 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.7 1998/12/30 23:03:34 ivan
+# bugfixes; fields isn't exported by derived classes
+#
+# Revision 1.6 1998/12/23 02:42:33 ivan
+# remove double '/' in link urls
+#
+# Revision 1.5 1998/12/23 02:36:28 ivan
+# use FS::cust_refund; to eliminate warning
+#
+# Revision 1.4 1998/12/17 09:57:21 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
+# Revision 1.3 1998/11/15 13:14:20 ivan
+# first pass as per-customer custom pricing
+#
+# Revision 1.2 1998/11/13 11:28:08 ivan
+# s/CGI-modules/CGI.pm/;, relative URL's with popurl
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use vars qw ( $cgi $query $custnum $cust_main $hashref $agent $referral
+ @packages $package @history @bills $bill @credits $credit
+ $balance $item @agents @referrals @invoicing_list $n1 $conf );
+use CGI;
use CGI::Carp qw(fatalsToBrowser);
use Date::Format;
use FS::UID qw(cgisuidsetup);
use FS::Record qw(qsearchs qsearch);
-use FS::CGI qw(header menubar);
-
-my($cgi) = new CGI::Base;
-$cgi->get;
+use FS::CGI qw(header menubar popurl table itable ntable);
+use FS::cust_credit;
+use FS::cust_pay;
+use FS::cust_bill;
+use FS::part_pkg;
+use FS::cust_pkg;
+use FS::part_referral;
+use FS::agent;
+use FS::cust_main;
+use FS::cust_refund;
+
+$cgi = new CGI;
&cgisuidsetup($cgi);
-SendHeaders(); # one guess.
-print header("Customer View", menubar(
- 'Main Menu' => '../',
-)),<<END;
- <BASEFONT SIZE=3>
-END
-
-#untaint custnum & get customer record
-$QUERY_STRING =~ /^(\d+)$/;
-my($custnum)=$1;
-my($cust_main)=qsearchs('cust_main',{'custnum'=>$custnum});
-die "Customer not found!" unless $cust_main;
-my($hashref)=$cust_main->hashref;
+$conf = new FS::Conf;
-#custnum
-print "<FONT SIZE=+1><CENTER>Customer #<B>$custnum</B></CENTER></FONT>",
- qq!<CENTER><A HREF="#cust_main">Customer Information</A> | !,
- qq!<A HREF="#cust_comments">Comments</A> | !,
- qq!<A HREF="#cust_pkg">Packages</A> | !,
- qq!<A HREF="#history">Payment History</A> </CENTER>!;
+print $cgi->header( '-expires' => 'now' ), header("Customer View", menubar(
+ 'Main Menu' => popurl(2)
+));
-#bill now linke
-print qq!<HR><CENTER><A HREF="../misc/bill.cgi?$custnum">!,
- qq!Bill this customer now</A></CENTER>!;
-
-#formatting
-print qq!<HR><A NAME="cust_main"><CENTER><FONT SIZE=+1>Customer Information!,
- qq!</FONT>!,
- qq!<BR><A HREF="../edit/cust_main.cgi?$custnum!,
- qq!">Edit this information</A></CENTER><FONT SIZE=-1>!;
-
-#agentnum
-my($agent)=qsearchs('agent',{
- 'agentnum' => $cust_main->getfield('agentnum')
-} );
-die "Agent not found!" unless $agent;
-print "<BR>Agent #<B>" , $agent->getfield('agentnum') , ": " ,
- $agent->getfield('agent') , "</B>";
-
-#refnum
-my($referral)=qsearchs('part_referral',{'refnum' => $cust_main->refnum});
-die "Referral not found!" unless $referral;
-print "<BR>Referral #<B>", $referral->refnum, ": ",
- $referral->referral, "<\B>";
-
-#last, first
-print "<P><B>", $hashref->{'last'}, ", ", $hashref->{first}, "</B>";
-
-#ss
-print " (SS# <B>", $hashref->{ss}, "</B>)" if $hashref->{ss};
-
-#company
-print "<BR><B>", $hashref->{company}, "</B>" if $hashref->{company};
-
-#address1
-print "<BR><B>", $hashref->{address1}, "</B>";
-
-#address2
-print "<BR><B>", $hashref->{address2}, "</B>" if $hashref->{address2};
-
-#city
-print "<BR><B>", $hashref->{city}, "</B>";
-
-#county
-print " (<B>", $hashref->{county}, "</B> county)" if $hashref->{county};
-
-#state
-print ",<B>", $hashref->{state}, "</B>";
-
-#zip
-print " <B>", $hashref->{zip}, "</B>";
-
-#country
-print "<BR><B>", $hashref->{country}, "</B>"
- unless $hashref->{country} eq "US";
-
-#daytime
-print "<P><B>", $hashref->{daytime}, "</B>" if $hashref->{daytime};
-print " (Day)" if $hashref->{daytime} && $hashref->{night};
-
-#night
-print "<BR><B>", $hashref->{night}, "</B>" if $hashref->{night};
-print " (Night)" if $hashref->{daytime} && $hashref->{night};
-
-#fax
-print "<BR><B>", $hashref->{fax}, "</B> (Fax)" if $hashref->{fax};
-
-#payby/payinfo/paydate/payname
-if ($hashref->{payby} eq "CARD") {
- print "<P>Card #<B>", $hashref->{payinfo}, "</B> Exp. <B>",
- $hashref->{paydate}, "</B>";
- print " (<B>", $hashref->{payname}, "</B>)" if $hashref->{payname};
-} elsif ($hashref->{payby} eq "BILL") {
- print "<P>Bill";
- print " on P.O. #<B>", $hashref->{payinfo}, "</B>"
- if $hashref->{payinfo};
- print " until <B>", $hashref->{paydate}, "</B>"
- if $hashref->{paydate};
- print " to <B>", $hashref->{payname}, "</B> at above address"
- if $hashref->{payname};
-} elsif ($hashref->{payby} eq "COMP") {
- print "<P>Access complimentary";
- print " courtesy of <B>", $hashref->{payinfo}, "</B>"
- if $hashref->{payinfo};
- print " until <B>", $hashref->{paydate}, "</B>"
- if $hashref->{paydate};
-} else {
- print "Unknown payment type ", $hashref->{payby}, "!";
+die "No customer specified (bad URL)!" unless $cgi->keywords;
+($query) = $cgi->keywords; # needs parens with my, ->keywords returns array
+$query =~ /^(\d+)$/;
+$custnum = $1;
+$cust_main = qsearchs('cust_main',{'custnum'=>$custnum});
+die "Customer not found!" unless $cust_main;
+$hashref = $cust_main->hashref;
+
+print &itable(), '<TR><TD><A NAME="cust_main"></A>';
+
+print qq!<A HREF="!, popurl(2),
+ qq!edit/cust_main.cgi?$custnum">Edit this customer</A>!;
+print qq! | <A HREF="!, popurl(2),
+ qq!misc/delete-customer.cgi?$custnum"> Delete this customer</A>!
+ if $conf->exists('deletecustomers');
+print &ntable("#c0c0c0"), "<TR><TD>", &ntable("#c0c0c0",2),
+ '<TR><TD ALIGN="right">Customer number</TD><TD BGCOLOR="#ffffff">',
+ $custnum, '</TD></TR>',
+;
+
+@agents = qsearch( 'agent', {} );
+unless ( scalar(@agents) == 1 ) {
+ $agent = qsearchs('agent',{
+ 'agentnum' => $cust_main->agentnum
+ } );
+ print '<TR><TD ALIGN="right">Agent</TD><TD BGCOLOR="#ffffff">',
+ $agent->agentnum, ": ", $agent->agent, '</TD></TR>';
+}
+@referrals = qsearch( 'part_referral', {} );
+unless ( scalar(@referrals) == 1 ) {
+ my $referral = qsearchs('part_referral', {
+ 'refnum' => $cust_main->refnum
+ } );
+ print '<TR><TD ALIGN="right">Referral</TD><TD BGCOLOR="#ffffff">',
+ $referral->refnum, ": ", $referral->referral, '</TD></TR>';
+}
+print '<TR><TD ALIGN="right">Order taker</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->otaker, '</TD></TR>';
+
+print '</TABLE></TD></TR></TABLE>';
+
+print '</TD><TD ROWSPAN=2>';
+
+print "Contact information", &ntable("#c0c0c0"), "<TR><TD>",
+ &ntable("#c0c0c0",2),
+ '<TR><TD ALIGN="right">Contact name<BR>(last, first)</TD>',
+ '<TD COLSPAN=3 BGCOLOR="#ffffff">',
+ $cust_main->last, ', ', $cust_main->first,
+ '</TD><TD ALIGN="right">SS#</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->ss || '&nbsp', '</TD></TR>',
+ '<TR><TD ALIGN="right">Company</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->company,
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Address</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->address1,
+ '</TD></TR>',
+;
+print '<TR><TD ALIGN="right">&nbsp;</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->address2, '</TD></TR>'
+ if $cust_main->address2;
+print '<TR><TD ALIGN="right">City</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->city,
+ '</TD><TD ALIGN="right">State</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->state,
+ '</TD><TD ALIGN="right">Zip</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->zip, '</TD></TR>',
+ '<TR><TD ALIGN="right">Country</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->country,
+ '</TD></TR>',
+;
+print '<TR><TD ALIGN="right">Day Phone</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->daytime || '&nbsp', '</TD></TR>',
+ '<TR><TD ALIGN="right">Night Phone</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->night || '&nbsp', '</TD></TR>',
+ '<TR><TD ALIGN="right">Fax</TD><TD COLSPAN=5 BGCOLOR="#ffffff">',
+ $cust_main->fax || '&nbsp', '</TD></TR>',
+ '</TABLE>', "</TD></TR></TABLE>"
+;
+
+print '</TD></TR><TR><TD>';
+
+@invoicing_list = $cust_main->invoicing_list;
+print "Billing information (",
+ qq!<A HREF="!, popurl(2), qq!/misc/bill.cgi?$custnum">!, "Bill now</A>)",
+ &ntable("#c0c0c0"), "<TR><TD>", &ntable("#c0c0c0",2),
+ '<TR><TD ALIGN="right">Tax exempt</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->tax ? 'yes' : 'no',
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Postal invoices</TD><TD BGCOLOR="#ffffff">',
+ ( grep { $_ eq 'POST' } @invoicing_list ) ? 'yes' : 'no',
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Email invoices</TD><TD BGCOLOR="#ffffff">',
+ join(', ', grep { $_ ne 'POST' } @invoicing_list ) || 'no',
+ '</TD></TR>',
+ '<TR><TD ALIGN="right">Billing type</TD><TD BGCOLOR="#ffffff">',
+;
+
+if ( $cust_main->payby eq 'CARD' ) {
+ print 'Credit card</TD></TR>',
+ '<TR><TD ALIGN="right">Card number</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payinfo, '</TD></TR>',
+ '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->paydate, '</TD></TR>',
+ '<TR><TD ALIGN="right">Name on card</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payname, '</TD></TR>'
+ ;
+} elsif ( $cust_main->payby eq 'BILL' ) {
+ print 'Billing</TD></TR>';
+ print '<TR><TD ALIGN="right">P.O. </TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payinfo, '</TD></TR>',
+ if $cust_main->payinfo;
+ print '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->paydate, '</TD></TR>',
+ '<TR><TD ALIGN="right">Attention</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payname, '</TD></TR>',
+ ;
+} elsif ( $cust_main->payby eq 'COMP' ) {
+ print 'Complimentary</TD></TR>',
+ '<TR><TD ALIGN="right">Authorized by</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->payinfo, '</TD></TR>',
+ '<TR><TD ALIGN="right">Expiration</TD><TD BGCOLOR="#ffffff">',
+ $cust_main->paydate, '</TD></TR>',
+ ;
}
-#tax
-print "<BR>(Tax exempt)" if $hashref->{tax};
-
-#otaker
-print "<P>Order taken by <B>", $hashref->{otaker}, "</B>";
+print "</TABLE></TD></TR></TABLE></TD></TR></TABLE>";
-#formatting
-print qq!<HR><FONT SIZE=+1><A NAME="cust_pkg"><CENTER>Packages</A></FONT>!,
- qq!<BR>Click on package number to view/edit package.!,
- qq!<BR><A HREF="../edit/cust_pkg.cgi?$custnum">Add/Edit packages</A>!,
- qq!</CENTER><BR>!;
+print qq!<BR><BR><A NAME="cust_pkg">Packages</A> !,
+# qq!<BR>Click on package number to view/edit package.!,
+ qq!( <A HREF="!, popurl(2), qq!edit/cust_pkg.cgi?$custnum">Order and cancel packages</A> )!,
+;
#display packages
#formatting
-print qq!<CENTER><TABLE BORDER=4>\n!,
- qq!<TR><TH ROWSPAN=2>#</TH><TH ROWSPAN=2>Package</TH><TH COLSPAN=5>!,
- qq!Dates</TH></TR>\n!,
+print qq!!, &table(), "\n",
+ qq!<TR><TH COLSPAN=2 ROWSPAN=2>Package</TH><TH COLSPAN=5>!,
+ qq!Dates</TH><TH COLSPAN=2 ROWSPAN=2>Services</TH></TR>\n!,
qq!<TR><TH><FONT SIZE=-1>Setup</FONT></TH><TH>!,
qq!<FONT SIZE=-1>Next bill</FONT>!,
qq!</TH><TH><FONT SIZE=-1>Susp.</FONT></TH><TH><FONT SIZE=-1>Expire!,
@@ -180,59 +260,76 @@ print qq!<CENTER><TABLE BORDER=4>\n!,
qq!</TR>\n!;
#get package info
-my(@packages)=qsearch('cust_pkg',{'custnum'=>$custnum});
-my($package);
-foreach $package (@packages) {
- my($pref)=$package->hashref;
- my($part_pkg)=qsearchs('part_pkg',{
- 'pkgpart' => $pref->{pkgpart}
- } );
- print qq!<TR><TD><FONT SIZE=-1><A HREF="../view/cust_pkg.cgi?!,
- $pref->{pkgnum}, qq!">!,
- $pref->{pkgnum}, qq!</A></FONT></TD>!,
- "<TD><FONT SIZE=-1>", $part_pkg->getfield('pkg'), " - ",
- $part_pkg->getfield('comment'), "</FONT></TD>",
- "<TD><FONT SIZE=-1>",
- $pref->{setup} ? time2str("%D",$pref->{setup} ) : "" ,
- "</FONT></TD>",
- "<TD><FONT SIZE=-1>",
- $pref->{bill} ? time2str("%D",$pref->{bill} ) : "" ,
- "</FONT></TD>",
- "<TD><FONT SIZE=-1>",
- $pref->{susp} ? time2str("%D",$pref->{susp} ) : "" ,
- "</FONT></TD>",
- "<TD><FONT SIZE=-1>",
- $pref->{expire} ? time2str("%D",$pref->{expire} ) : "" ,
- "</FONT></TD>",
- "<TD><FONT SIZE=-1>",
- $pref->{cancel} ? time2str("%D",$pref->{cancel} ) : "" ,
- "</FONT></TD>",
- "</TR>";
+if ( $conf->exists('hidecancelledpackages') ) {
+ @packages = $cust_main->ncancelled_pkgs;
+} else {
+ @packages = $cust_main->all_pkgs;
}
+$n1 = '<TR>';
+foreach $package (@packages) {
+ my $pkgnum = $package->pkgnum;
+ my $pkg = $package->part_pkg->pkg;
+ my $comment = $package->part_pkg->comment;
+ my $pkgview = popurl(2). "view/cust_pkg.cgi?$pkgnum";
+ my @cust_svc = qsearch( 'cust_svc', { 'pkgnum' => $pkgnum } );
+ my $rowspan = scalar(@cust_svc) || 1;
+
+ my $button_cgi = new CGI;
+ $button_cgi->param('clone', $package->part_pkg->pkgpart);
+ $button_cgi->param('pkgnum', $package->pkgnum);
+ my $button_url = popurl(2). "edit/part_pkg.cgi?". $button_cgi->query_string;
+
+ #print $n1, qq!<TD ROWSPAN=$rowspan><A HREF="$pkgview">$pkgnum</A></TD>!,
+ print $n1, qq!<TD ROWSPAN=$rowspan>$pkgnum</TD>!,
+ qq!<TD ROWSPAN=$rowspan><FONT SIZE=-1>!,
+ #qq!<A HREF="$pkgview">$pkg - $comment</A>!,
+ qq!$pkg - $comment!,
+ qq! ( <A HREF="$pkgview">Edit</A> | <A HREF="$button_url">Customize pricing</A> )</FONT></TD>!,
+ ;
+ for ( qw( setup bill susp expire cancel ) ) {
+ print "<TD ROWSPAN=$rowspan><FONT SIZE=-1>", ( $package->getfield($_)
+ ? time2str("%D", $package->getfield($_) )
+ : '&nbsp'
+ ), '</FONT></TD>',
+ ;
+ }
+
+ my $n2 = '';
+ foreach my $cust_svc ( @cust_svc ) {
+ my($label, $value, $svcdb) = $cust_svc->label;
+ my($svcnum) = $cust_svc->svcnum;
+ my($sview) = popurl(2). "view";
+ print $n2,qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$label</FONT></A></TD>!,
+ qq!<TD><A HREF="$sview/$svcdb.cgi?$svcnum"><FONT SIZE=-1>$value</FONT></A></TD>!;
+ $n2="</TR><TR>";
+ }
+ $n1="</TR><TR>";
+}
+print "</TR>";
+
#formatting
-print "</TABLE></CENTER>";
+print "</TABLE>";
#formatting
-print qq!<CENTER><HR><A NAME="history"><FONT SIZE=+1>Payment History!,
- qq!</FONT></A><BR>!,
- qq!Click on invoice to view invoice/enter payment.<BR>!,
- qq!<A HREF="../edit/cust_credit.cgi?$custnum">!,
- qq!Post Credit / Refund</A></CENTER><BR>!;
+print qq!<BR><BR><A NAME="history">Payment History!,
+ qq!</A>!,
+ qq! ( Click on invoice to view invoice/enter payment. | !,
+ qq!<A HREF="!, popurl(2), qq!edit/cust_credit.cgi?$custnum">!,
+ qq!Post credit / refund</A> )!;
#get payment history
#
# major problem: this whole thing is way too sloppy.
# minor problem: the description lines need better formatting.
-my(@history);
+@history = (); #needed for mod_perl :)
-my(@bills)=qsearch('cust_bill',{'custnum'=>$custnum});
-my($bill);
+@bills = qsearch('cust_bill',{'custnum'=>$custnum});
foreach $bill (@bills) {
my($bref)=$bill->hashref;
push @history,
- $bref->{_date} . qq!\t<A HREF="../view/cust_bill.cgi?! .
+ $bref->{_date} . qq!\t<A HREF="!. popurl(2). qq!view/cust_bill.cgi?! .
$bref->{invnum} . qq!">Invoice #! . $bref->{invnum} .
qq! (Balance \$! . $bref->{owed} . qq!)</A>\t! .
$bref->{charged} . qq!\t\t\t!;
@@ -240,7 +337,6 @@ foreach $bill (@bills) {
my(@payments)=qsearch('cust_pay',{'invnum'=> $bref->{invnum} } );
my($payment);
foreach $payment (@payments) {
-# my($pref)=$payment->hashref;
my($date,$invnum,$payby,$payinfo,$paid)=($payment->getfield('_date'),
$payment->getfield('invnum'),
$payment->getfield('payby'),
@@ -252,8 +348,7 @@ foreach $bill (@bills) {
}
}
-my(@credits)=qsearch('cust_credit',{'custnum'=>$custnum});
-my($credit);
+@credits = qsearch('cust_credit',{'custnum'=>$custnum});
foreach $credit (@credits) {
my($cref)=$credit->hashref;
push @history,
@@ -274,8 +369,7 @@ foreach $credit (@credits) {
}
#formatting
- print <<END;
-<CENTER><TABLE BORDER=4>
+ print &table(), <<END;
<TR>
<TH>Date</TH>
<TH>Description</TH>
@@ -289,8 +383,7 @@ END
#display payment history
-my($balance)=0;
-my($item);
+$balance = 0;
foreach $item (sort keyfield_numerically @history) {
my($date,$desc,$charge,$payment,$credit,$refund)=split(/\t/,$item);
$charge ||= 0;
@@ -320,7 +413,7 @@ foreach $item (sort keyfield_numerically @history) {
}
#formatting
-print "</TABLE></CENTER>";
+print "</TABLE>";
#end
diff --git a/htdocs/view/cust_pkg.cgi b/htdocs/view/cust_pkg.cgi
index 04e38326a..0054ee0fa 100755
--- a/htdocs/view/cust_pkg.cgi
+++ b/htdocs/view/cust_pkg.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# cust_pkg.cgi: View a package
+# $Id: cust_pkg.cgi,v 1.11 1999-04-09 04:22:34 ivan Exp $
#
# Usage: cust_pkg.cgi pkgnum
# http://server.name/path/cust_pkg.cgi?pkgnum
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 96-dec-15
#
# services section needs to be cleaned up, needs to display extraneous
@@ -24,118 +22,140 @@
# ivan@voicenet.com 97-jul-29
#
# no FS::Search ivan@sisd.com 98-mar-7
+#
+# $Log: cust_pkg.cgi,v $
+# Revision 1.11 1999-04-09 04:22:34 ivan
+# also table()
+#
+# Revision 1.10 1999/04/09 03:52:55 ivan
+# explicit & for table/itable/ntable
+#
+# Revision 1.9 1999/04/08 12:00:19 ivan
+# aesthetic update
+#
+# Revision 1.8 1999/02/28 00:04:01 ivan
+# removed misleading comments
+#
+# Revision 1.7 1999/01/19 05:14:20 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 09:41:44 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.5 1998/12/23 03:11:40 ivan
+# *** empty log message ***
+#
+# Revision 1.3 1998/12/17 09:57:22 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
+# Revision 1.2 1998/11/13 09:56:49 ivan
+# change configuration file layout to support multiple distinct databases (with
+# own set of config files, export, etc.)
+#
use strict;
+use vars qw ( $cgi %uiview %uiadd $part_svc $query $pkgnum $cust_pkg $part_pkg
+ $custnum $susp $cancel $expire $pkg $comment $setup $bill
+ $otaker );
use Date::Format;
-use CGI::Base qw(:DEFAULT :CGI); # CGI module
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(popurl header menubar ntable table);
use FS::Record qw(qsearch qsearchs);
+use FS::part_svc;
+use FS::cust_pkg;
+use FS::part_pkg;
+use FS::pkg_svc;
+use FS::cust_svc;
-my($cgi) = new CGI::Base;
-$cgi->get;
-&cgisuidsetup($cgi);
+$cgi = new CGI;
+cgisuidsetup($cgi);
-my(%uiview,%uiadd);
-my($part_svc);
foreach $part_svc ( qsearch('part_svc',{}) ) {
- $uiview{$part_svc->svcpart}="../view/". $part_svc->svcdb . ".cgi";
- $uiadd{$part_svc->svcpart}="../edit/". $part_svc->svcdb . ".cgi";
+ $uiview{$part_svc->svcpart} = popurl(2). "view/". $part_svc->svcdb . ".cgi";
+ $uiadd{$part_svc->svcpart}= popurl(2). "edit/". $part_svc->svcdb . ".cgi";
}
-SendHeaders(); # one guess.
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Package View</TITLE>
- </HEAD>
- <BODY>
- <CENTER>
- <H1>Package View</H1>
- </CENTER>
- <BASEFONT SIZE=3>
-END
-
-#untaint pkgnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($pkgnum)=$1;
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+$pkgnum = $1;
#get package record
-my($cust_pkg)=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
+$cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
die "No package!" unless $cust_pkg;
-my($part_pkg)=qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->getfield('pkgpart')});
+$part_pkg = qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->getfield('pkgpart')});
-#nav bar
-my($custnum)=$cust_pkg->getfield('custnum');
-print qq!<CENTER><A HREF="../view/cust_main.cgi?$custnum">View this customer!,
- qq! (#$custnum)</A> | <A HREF="../">Main menu</A></CENTER><BR>!;
+$custnum = $cust_pkg->getfield('custnum');
+print $cgi->header( '-expires' => 'now' ), header('Package View', menubar(
+ "View this customer (#$custnum)" => popurl(2). "view/cust_main.cgi?$custnum",
+ 'Main Menu' => popurl(2)
+));
#print info
-my($susp,$cancel,$expire)=(
+($susp,$cancel,$expire)=(
$cust_pkg->getfield('susp'),
$cust_pkg->getfield('cancel'),
$cust_pkg->getfield('expire'),
);
-print "<FONT SIZE=+1><CENTER>Package #<B>$pkgnum</B></FONT>";
-print qq!<BR><A HREF="#package">Package Information</A>!;
-print qq! | <A HREF="#services">Service Information</A>! unless $cancel;
-print qq!</CENTER><HR>\n!;
-
-my($pkg,$comment)=($part_pkg->getfield('pkg'),$part_pkg->getfield('comment'));
-print qq!<A NAME="package"><CENTER><FONT SIZE=+1>Package Information!,
- qq!</FONT></A>!;
-print qq!<BR><A HREF="../unimp.html">Edit this information</A></CENTER>!;
-print "<P>Package: <B>$pkg - $comment</B>";
-
-my($setup,$bill)=($cust_pkg->getfield('setup'),$cust_pkg->getfield('bill'));
-print "<BR>Setup: <B>", $setup ? time2str("%D",$setup) : "(Not setup)" ,"</B>";
-print "<BR>Next bill: <B>", $bill ? time2str("%D",$bill) : "" ,"</B>";
-
-if ($susp) {
- print "<BR>Suspended: <B>", time2str("%D",$susp), "</B>";
- print qq! <A HREF="../misc/unsusp_pkg.cgi?$pkgnum">Unsuspend</A>! unless $cancel;
-} else {
- print qq!<BR><A HREF="../misc/susp_pkg.cgi?$pkgnum">Suspend</A>! unless $cancel;
-}
-
-if ($expire) {
- print "<BR>Expire: <B>", time2str("%D",$expire), "</B>";
-}
- print <<END;
-<FORM ACTION="../misc/expire_pkg.cgi" METHOD="post">
-<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">
-Expire (date): <INPUT TYPE="text" NAME="date" VALUE="" >
-<INPUT TYPE="submit" VALUE="Cancel later">
-END
-
-if ($cancel) {
- print "<BR>Cancelled: <B>", time2str("%D",$cancel), "</B>";
-} else {
- print qq!<BR><A HREF="../misc/cancel_pkg.cgi?$pkgnum">Cancel now</A>!;
-}
-
-#otaker
-my($otaker)=$cust_pkg->getfield('otaker');
-print "<P>Order taken by <B>$otaker</B>";
+($pkg,$comment)=($part_pkg->getfield('pkg'),$part_pkg->getfield('comment'));
+($setup,$bill)=($cust_pkg->getfield('setup'),$cust_pkg->getfield('bill'));
+$otaker = $cust_pkg->getfield('otaker');
+
+print "Package information";
+print ' (<A HREF="'. popurl(2). 'misc/unsusp_pkg.cgi?'. $pkgnum.
+ '">unsuspend</A>)' if ( $susp && ! $cancel );
+print ' (<A HREF="'. popurl(2). 'misc/susp_pkg.cgi?'. $pkgnum.
+ '">suspend</A>)' unless ( $susp || $cancel );
+print ' (<A HREF="'. popurl(2). 'misc/cancel_pkg.cgi?'. $pkgnum.
+ '">cancel</A>)' unless $cancel;
+
+print &ntable("#c0c0c0"), '<TR><TD>', &ntable("#c0c0c0",2),
+ '<TR><TD ALIGN="right">Package number</TD><TD BGCOLOR="#ffffff">',
+ $pkgnum, '</TD></TR>',
+ '<TR><TD ALIGN="right">Package</TD><TD BGCOLOR="#ffffff">',
+ $pkg, '</TD></TR>',
+ '<TR><TD ALIGN="right">Comment</TD><TD BGCOLOR="#ffffff">',
+ $comment, '</TD></TR>',
+ '<TR><TD ALIGN="right">Setup date</TD><TD BGCOLOR="#ffffff">',
+ ( $setup ? time2str("%D",$setup) : "(Not setup)" ), '</TD></TR>',
+ '<TR><TD ALIGN="right">Next bill date</TD><TD BGCOLOR="#ffffff">',
+ ( $bill ? time2str("%D",$bill) : "&nbsp;" ), '</TD></TR>',
+;
+print '<TR><TD ALIGN="right">Suspension date</TD><TD BGCOLOR="#ffffff">',
+ time2str("%D",$susp), '</TD></TR>' if $susp;
+print '<TR><TD ALIGN="right">Expiration date</TD><TD BGCOLOR="#ffffff">',
+ time2str("%D",$expire), '</TD></TR>' if $expire;
+print '<TR><TD ALIGN="right">Cancellation date</TD><TD BGCOLOR="#ffffff">',
+ time2str("%D",$cancel), '</TD></TR>' if $cancel;
+print '<TR><TD ALIGN="right">Order taker</TD><TD BGCOLOR="#ffffff">',
+ $otaker, '</TD></TR>',
+ '</TABLE></TD></TR></TABLE>'
+;
+
+# print <<END;
+#<FORM ACTION="../misc/expire_pkg.cgi" METHOD="post">
+#<INPUT TYPE="hidden" NAME="pkgnum" VALUE="$pkgnum">
+#Expire (date): <INPUT TYPE="text" NAME="date" VALUE="" >
+#<INPUT TYPE="submit" VALUE="Cancel later">
+#END
unless ($cancel) {
#services
- print <<END;
-<HR><A NAME="services"><CENTER><FONT SIZE=+1>Service Information</FONT></A>
-<BR>Click on service to view/edit/add service.</CENTER><BR>
-<CENTER><B>Do NOT pick the "Link to existing" option unless you are auditing!!!</B></CENTER>
-<CENTER><TABLE BORDER=4>
-<TR><TH>Service</TH>
-END
+ print '<BR>Service Information', &table();
#list of services this pkgpart includes
- my($pkg_svc,%pkg_svc);
+ my $pkg_svc;
+ my %pkg_svc = ();
foreach $pkg_svc ( qsearch('pkg_svc',{'pkgpart'=> $cust_pkg->pkgpart }) ) {
$pkg_svc{$pkg_svc->svcpart} = $pkg_svc->quantity if $pkg_svc->quantity;
}
#list of records from cust_svc
- my($svcpart);
+ my $svcpart;
foreach $svcpart (sort {$a <=> $b} keys %pkg_svc) {
my($svc)=qsearchs('part_svc',{'svcpart'=>$svcpart})->getfield('svc');
@@ -150,8 +170,9 @@ END
my($cust_svc);
if ( $cust_svc=shift @cust_svc ) {
my($svcnum)=$cust_svc->svcnum;
+ my($label, $value, $svcdb) = $cust_svc->label;
print <<END;
-<TR><TD><A HREF="$uiview{$svcpart}?$svcnum">(View) $svc<A></TD></TR>
+<TR><TD><A HREF="$uiview{$svcpart}?$svcnum">(View) $svc: $value<A></TD></TR>
END
} else {
print <<END;
@@ -169,8 +190,12 @@ END
warn "WARNING: Leftover services pkgnum $pkgnum!" if @cust_svc;;
}
- print "</TABLE></CENTER>";
-
+ print "</TABLE><FONT SIZE=-1>",
+ "Choose (View) to view or edit an existing service<BR>",
+ "Choose (Add) to setup a new service<BR>",
+ "Choose (Link to existing) to link to a legacy (pre-Freeside) service",
+ "</FONT>"
+ ;
}
#formatting
diff --git a/htdocs/view/svc_acct.cgi b/htdocs/view/svc_acct.cgi
index 7096c2fb1..e203c7ec0 100755
--- a/htdocs/view/svc_acct.cgi
+++ b/htdocs/view/svc_acct.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# View svc_acct records
+# $Id: svc_acct.cgi,v 1.10 1999-04-14 11:27:06 ivan Exp $
#
# Usage: svc_acct.cgi svcnum
# http://server.name/path/svc_acct.cgi?svcnum
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 96-dec-17
#
# added link to send info
@@ -33,122 +31,130 @@
# /var/spool/freeside/conf/domain ivan@sisd.com 98-jul-17
#
# displays arbitrary radius attributes ivan@sisd.com 98-aug-16
+#
+# $Log: svc_acct.cgi,v $
+# Revision 1.10 1999-04-14 11:27:06 ivan
+# showpasswords config option to show passwords
+#
+# Revision 1.9 1999/04/08 12:00:19 ivan
+# aesthetic update
+#
+# Revision 1.8 1999/02/28 00:04:02 ivan
+# removed misleading comments
+#
+# Revision 1.7 1999/01/19 05:14:21 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.6 1999/01/18 09:41:45 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.5 1999/01/18 09:22:36 ivan
+# changes to track email addresses for email invoicing
+#
+# Revision 1.4 1998/12/23 03:09:19 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.3 1998/12/17 09:57:23 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
+# Revision 1.2 1998/12/16 05:24:29 ivan
+# use FS::Conf;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
-use CGI::Carp qw(fatalsToBrowser);
-use FS::UID qw(cgisuidsetup);
-use FS::Record qw(qsearchs fields);
-
-my($conf_domain)="/var/spool/freeside/conf/domain";
-open(DOMAIN,$conf_domain) or die "Can't open $conf_domain: $!";
-my($mydomain)=map {
- /^(.*)$/ or die "Illegal line in $conf_domain!"; #yes, we trust the file
- $1;
-} grep $_ !~ /^(#|$)/, <DOMAIN>;
-
-my($cgi) = new CGI::Base;
-$cgi->get;
+use vars qw( $conf $cgi $mydomain $query $svcnum $svc_acct $cust_svc $pkgnum
+ $cust_pkg $custnum $part_svc $p $svc_acct_pop $password );
+use CGI;
+use CGI::Carp qw( fatalsToBrowser );
+use FS::UID qw( cgisuidsetup );
+use FS::CGI qw( header popurl menubar);
+use FS::Record qw( qsearchs fields );
+use FS::Conf;
+use FS::svc_acct;
+use FS::cust_svc;
+use FS::cust_pkg;
+use FS::part_svc;
+use FS::svc_acct_pop;
+
+$cgi = new CGI;
&cgisuidsetup($cgi);
-#untaint svcnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($svcnum)=$1;
-my($svc_acct)=qsearchs('svc_acct',{'svcnum'=>$svcnum});
+$conf = new FS::Conf;
+$mydomain = $conf->config('domain');
+
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+$svcnum = $1;
+$svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum});
die "Unkonwn svcnum" unless $svc_acct;
-my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum});
-my($pkgnum)=$cust_svc->getfield('pkgnum');
-my($cust_pkg,$custnum);
+$cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+$pkgnum = $cust_svc->getfield('pkgnum');
if ($pkgnum) {
$cust_pkg=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
$custnum=$cust_pkg->getfield('custnum');
+} else {
+ $cust_pkg = '';
+ $custnum = '';
}
-my($part_svc)=qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
+$part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
die "Unkonwn svcpart" unless $part_svc;
-SendHeaders(); # one guess.
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Account View</TITLE>
- </HEAD>
- <BODY>
- <CENTER><H1>Account View</H1>
- <BASEFONT SIZE=3>
-<CENTER>
-END
+$p = popurl(2);
+print $cgi->header( '-expires' => 'now' ), header('Account View', menubar(
+ ( ( $pkgnum || $custnum )
+ ? ( "View this package (#$pkgnum)" => "${p}view/cust_pkg.cgi?$pkgnum",
+ "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) account" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+));
-if ($pkgnum || $custnum) {
- print <<END;
-<A HREF="../view/cust_pkg.cgi?$pkgnum">View this package (#$pkgnum)</A> |
-<A HREF="../view/cust_main.cgi?$custnum">View this customer (#$custnum)</A> |
-END
-} else {
- print <<END;
-<A HREF="../misc/cancel-unaudited.cgi?$svcnum">Cancel this (unaudited)account</A> |
-END
-}
-
-print <<END;
-<A HREF="../">Main menu</A></CENTER><BR>
-<FONT SIZE=+1>Service #$svcnum</FONT>
-END
-
-print qq!<BR><A HREF="../edit/svc_acct.cgi?$svcnum">Edit this information</A>!;
#print qq!<BR><A HREF="../misc/sendconfig.cgi?$svcnum">Send account information</A>!;
-print qq!<BR><BR><A HREF="#general">General</A> | <A HREF="#shell">Shell account</A> | !;
-print qq!<A HREF="#slip">SLIP/PPP account</A></CENTER>!;
-#formatting
-print qq!<HR><CENTER><FONT SIZE=+1><A NAME="general">General</A></FONT></CENTER>!;
-
-#svc
-print "Service: <B>", $part_svc->svc, "</B>";
-
-#username
-print "<BR>Username: <B>", $svc_acct->username, "</B>";
-
-#password
-if (substr($svc_acct->_password,0,1) eq "*") {
- print "<BR>Password: <I>(Login disabled)</I><BR>";
+print qq!<A HREF="${p}edit/svc_acct.cgi?$svcnum">Edit this information</A>!,
+ "<BR>Service #$svcnum",
+ "<BR>Service: <B>", $part_svc->svc, "</B>",
+ "<BR><BR>Username: <B>", $svc_acct->username, "</B>"
+;
+
+print "<BR>Password: ";
+$password = $svc_acct->_password;
+if ( $password =~ /^\*\w+\* (.*)$/ ) {
+ $password = $1;
+ print "<I>(login disabled)</I> ";
+}
+if ( $conf->exists('showpasswords') ) {
+ print "<B>$password</B>";
} else {
- print "<BR>Password: <I>(hidden)</I><BR>";
+ print "<I>(hidden)</I>";
}
+$password = '';
-# popnum -> svc_acct_pop record
-my($svc_acct_pop)=qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum});
-
-#pop
-print "POP: <B>", $svc_acct_pop->city, ", ", $svc_acct_pop->state,
+$svc_acct_pop = qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum});
+print "<BR>POP: <B>", $svc_acct_pop->city, ", ", $svc_acct_pop->state,
" (", $svc_acct_pop->ac, ")/", $svc_acct_pop->exch, "<\B>"
if $svc_acct_pop;
-#shell account
-print qq!<HR><CENTER><FONT SIZE=+1><A NAME="shell">!;
if ($svc_acct->uid ne '') {
- print "Shell account";
- print "</A></FONT></CENTER>";
- print "Uid: <B>", $svc_acct->uid, "</B>";
- print "<BR>Gid: <B>", $svc_acct->gid, "</B>";
-
- print qq!<BR>Finger name: <B>!, $svc_acct->finger, qq!</B><BR>!;
-
- print "Home directory: <B>", $svc_acct->dir, "</B><BR>";
-
- print "Shell: <B>", $svc_acct->shell, "</B><BR>";
-
- print "Quota: <B>", $svc_acct->quota, "</B> <I>(unimplemented)</I>";
+ print "<BR><BR>Uid: <B>", $svc_acct->uid, "</B>",
+ "<BR>Gid: <B>", $svc_acct->gid, "</B>",
+ "<BR>Finger name: <B>", $svc_acct->finger, "</B>",
+ "<BR>Home directory: <B>", $svc_acct->dir, "</B>",
+ "<BR>Shell: <B>", $svc_acct->shell, "</B>",
+ "<BR>Quota: <B>", $svc_acct->quota, "</B> <I>(unimplemented)</I>"
+ ;
} else {
- print "No shell account.</A></FONT></CENTER>";
+ print "<BR><BR>(No shell account)";
}
-# SLIP/PPP
-print qq!<HR><CENTER><FONT SIZE=+1><A NAME="slip">!;
if ($svc_acct->slipip) {
- print "SLIP/PPP account</A></FONT></CENTER>";
- print "IP address: <B>", ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' ) ? "<I>(Dynamic)</I>" : $svc_acct->slipip ,"</B>";
+ print "<BR><BR>IP address: <B>", ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' ) ? "<I>(Dynamic)</I>" : $svc_acct->slipip ,"</B>";
my($attribute);
foreach $attribute ( grep /^radius_/, fields('svc_acct') ) {
#warn $attribute;
@@ -158,15 +164,8 @@ if ($svc_acct->slipip) {
print "<BR>Radius $pattribute: <B>". $svc_acct->getfield($attribute), "</B>";
}
} else {
- print "No SLIP/PPP account</A></FONT></CENTER>"
+ print "<BR><BR>(No SLIP/PPP account)";
}
-print "<HR>";
-
- #formatting
- print <<END;
-
- </BODY>
-</HTML>
-END
+print "</BODY></HTML>";
diff --git a/htdocs/view/svc_acct_sm.cgi b/htdocs/view/svc_acct_sm.cgi
index 42623eefd..51fbc0351 100755
--- a/htdocs/view/svc_acct_sm.cgi
+++ b/htdocs/view/svc_acct_sm.cgi
@@ -1,12 +1,10 @@
#!/usr/bin/perl -Tw
#
-# View svc_acct_sm records
+# $Id: svc_acct_sm.cgi,v 1.10 1999-04-08 12:00:19 ivan Exp $
#
# Usage: svc_acct_sm.cgi svcnum
# http://server.name/path/svc_acct_sm.cgi?svcnum
#
-# Note: Should be run setuid freeside as user nobody.
-#
# based on view/svc_acct.cgi
#
# ivan@voicenet.com 97-jan-5
@@ -20,95 +18,106 @@
# bmccane@maxbaud.net 98-apr-3
#
# /var/spool/freeside/conf/domain ivan@sisd.com 98-jul-17
+#
+# $Log: svc_acct_sm.cgi,v $
+# Revision 1.10 1999-04-08 12:00:19 ivan
+# aesthetic update
+#
+# Revision 1.9 1999/02/28 00:04:03 ivan
+# removed misleading comments
+#
+# Revision 1.8 1999/02/09 09:23:00 ivan
+# visual and bugfixes
+#
+# Revision 1.7 1999/02/07 09:59:42 ivan
+# more mod_perl fixes, and bugfixes Peter Wemm sent via email
+#
+# Revision 1.6 1999/01/19 05:14:22 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:46 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1998/12/23 03:09:52 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.3 1998/12/17 09:57:24 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
+# Revision 1.2 1998/12/16 05:24:30 ivan
+# use FS::Conf;
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw($conf $cgi $mydomain $query $svcnum $svc_acct_sm $cust_svc
+ $pkgnum $cust_pkg $custnum $part_svc $p $domsvc $domuid $domuser
+ $svc $svc_domain $domain $svc_acct $username );
+use CGI;
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(header popurl menubar );
use FS::Record qw(qsearchs);
-
-my($conf_domain)="/var/spool/freeside/conf/domain";
-open(DOMAIN,$conf_domain) or die "Can't open $conf_domain: $!";
-my($mydomain)=map {
- /^(.*)$/ or die "Illegal line in $conf_domain!"; #yes, we trust the file
- $1
-} grep $_ !~ /^(#|$)/, <DOMAIN>;
-close DOMAIN;
-
-my($cgi) = new CGI::Base;
-$cgi->get;
+use FS::Conf;
+use FS::svc_acct_sm;
+use FS::cust_svc;
+use FS::cust_pkg;
+use FS::part_svc;
+use FS::svc_domain;
+use FS::svc_acct;
+
+$cgi = new CGI;
cgisuidsetup($cgi);
-#untaint svcnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($svcnum)=$1;
-my($svc_acct_sm)=qsearchs('svc_acct_sm',{'svcnum'=>$svcnum});
+$conf = new FS::Conf;
+$mydomain = $conf->config('domain');
+
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+$svcnum = $1;
+$svc_acct_sm = qsearchs('svc_acct_sm',{'svcnum'=>$svcnum});
die "Unknown svcnum" unless $svc_acct_sm;
-my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum});
-my($pkgnum)=$cust_svc->getfield('pkgnum');
-my($cust_pkg,$custnum);
+$cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+$pkgnum = $cust_svc->getfield('pkgnum');
if ($pkgnum) {
$cust_pkg=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
$custnum=$cust_pkg->getfield('custnum');
-}
-
-my($part_svc)=qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
-die "Unkonwn svcpart" unless $part_svc;
-
-SendHeaders(); # one guess.
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Mail Alias View</TITLE>
- </HEAD>
- <BODY>
- <CENTER><H1>Mail Alias View</H1>
-END
-if ($pkgnum || $custnum) {
- print <<END;
-<A HREF="../view/cust_pkg.cgi?$pkgnum">View this package (#$pkgnum)</A> |
-<A HREF="../view/cust_main.cgi?$custnum">View this customer (#$custnum)</A> |
-END
} else {
- print <<END;
-<A HREF="../misc/cancel-unaudited.cgi?$svcnum">Cancel this (unaudited)account</A> |
-END
+ $cust_pkg = '';
+ $custnum = '';
}
-print <<END;
- <A HREF="../">Main menu</A></CENTER><BR<
- <FONT SIZE=+1>Service #$svcnum</FONT>
- <P><A HREF="../edit/svc_acct_sm.cgi?$svcnum">Edit this information</A>
- <BASEFONT SIZE=3>
-END
+$part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
+die "Unkonwn svcpart" unless $part_svc;
-my($domsvc,$domuid,$domuser)=(
+$p = popurl(2);
+print $cgi->header( '-expires' => 'now' ), header('Mail Alias View', menubar(
+ ( ( $pkgnum || $custnum )
+ ? ( "View this package (#$pkgnum)" => "${p}view/cust_pkg.cgi?$pkgnum",
+ "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) account" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+));
+
+($domsvc,$domuid,$domuser) = (
$svc_acct_sm->domsvc,
$svc_acct_sm->domuid,
$svc_acct_sm->domuser,
);
-my($svc) = $part_svc->svc;
-my($svc_domain)=qsearchs('svc_domain',{'svcnum'=>$domsvc});
-my($domain)=$svc_domain->domain;
-my($svc_acct)=qsearchs('svc_acct',{'uid'=>$domuid});
-my($username)=$svc_acct->username;
-
-#formatting
-print qq!<HR>!;
-
-#svc
-print "Service: <B>$svc</B>";
-
-print "<HR>";
-
-print qq!Mail to <B>!, ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser ) , qq!</B>\@<B>$domain</B> forwards to <B>$username</B>\@$mydomain mailbox.!;
-
-print "<HR>";
-
- #formatting
- print <<END;
-
- </BODY>
-</HTML>
-END
+$svc = $part_svc->svc;
+$svc_domain = qsearchs('svc_domain',{'svcnum'=>$domsvc});
+$domain = $svc_domain->domain;
+$svc_acct = qsearchs('svc_acct',{'uid'=>$domuid});
+$username = $svc_acct->username;
+
+print qq!<A HREF="${p}edit/svc_acct_sm.cgi?$svcnum">Edit this information</A>!,
+ "<BR>Service #$svcnum",
+ "<BR>Service: <B>$svc</B>",
+ qq!<BR>Mail to <B>!, ( ($domuser eq '*') ? "<I>(anything)</I>" : $domuser ) , qq!</B>\@<B>$domain</B> forwards to <B>$username</B>\@$mydomain mailbox.!,
+ '</BODY></HTML>'
+;
diff --git a/htdocs/view/svc_domain.cgi b/htdocs/view/svc_domain.cgi
index 78ff6ac0b..fef5ad4f3 100755
--- a/htdocs/view/svc_domain.cgi
+++ b/htdocs/view/svc_domain.cgi
@@ -1,76 +1,99 @@
#!/usr/bin/perl -Tw
#
-# View svc_domain records
+# $Id: svc_domain.cgi,v 1.10 1999-08-27 22:18:44 ivan Exp $
#
# Usage: svc_domain svcnum
# http://server.name/path/svc_domain.cgi?svcnum
#
-# Note: Should be run setuid freeside as user nobody.
-#
# ivan@voicenet.com 97-jan-6
#
# rewrite ivan@sisd.com 98-mar-14
#
# Changes to allow page to work at a relative position in server
# bmccane@maxbaud.net 98-apr-3
+#
+# $Log: svc_domain.cgi,v $
+# Revision 1.10 1999-08-27 22:18:44 ivan
+# point to patrick instead of internic!
+#
+# Revision 1.9 1999/04/08 12:00:19 ivan
+# aesthetic update
+#
+# Revision 1.8 1999/02/28 00:04:04 ivan
+# removed misleading comments
+#
+# Revision 1.7 1999/02/23 08:09:25 ivan
+# beginnings of one-screen new customer entry and some other miscellania
+#
+# Revision 1.6 1999/01/19 05:14:23 ivan
+# for mod_perl: no more top-level my() variables; use vars instead
+# also the last s/create/new/;
+#
+# Revision 1.5 1999/01/18 09:41:47 ivan
+# all $cgi->header calls now include ( '-expires' => 'now' ) for mod_perl
+# (good idea anyway)
+#
+# Revision 1.4 1998/12/23 03:10:19 ivan
+# $cgi->keywords instead of $cgi->query_string
+#
+# Revision 1.3 1998/12/17 09:57:25 ivan
+# s/CGI::(Base|Request)/CGI.pm/;
+#
+# Revision 1.2 1998/11/13 09:56:50 ivan
+# change configuration file layout to support multiple distinct databases (with
+# own set of config files, export, etc.)
+#
use strict;
-use CGI::Base qw(:DEFAULT :CGI);
+use vars qw( $cgi $query $svcnum $svc_domain $domain $cust_svc $pkgnum
+ $cust_pkg $custnum $part_svc $p );
+use CGI;
use FS::UID qw(cgisuidsetup);
+use FS::CGI qw(header menubar popurl menubar);
use FS::Record qw(qsearchs);
+use FS::svc_domain;
+use FS::cust_svc;
+use FS::cust_pkg;
+use FS::part_svc;
-my($cgi) = new CGI::Base;
-$cgi->get;
+$cgi = new CGI;
cgisuidsetup($cgi);
-#untaint svcnum
-$QUERY_STRING =~ /^(\d+)$/;
-my($svcnum)=$1;
-my($svc_domain)=qsearchs('svc_domain',{'svcnum'=>$svcnum});
+($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+$svcnum = $1;
+$svc_domain = qsearchs('svc_domain',{'svcnum'=>$svcnum});
die "Unknown svcnum" unless $svc_domain;
-my($domain)=$svc_domain->domain;
-my($cust_svc)=qsearchs('cust_svc',{'svcnum'=>$svcnum});
-my($pkgnum)=$cust_svc->getfield('pkgnum');
-my($cust_pkg,$custnum);
+$cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum});
+$pkgnum = $cust_svc->getfield('pkgnum');
if ($pkgnum) {
$cust_pkg=qsearchs('cust_pkg',{'pkgnum'=>$pkgnum});
$custnum=$cust_pkg->getfield('custnum');
+} else {
+ $cust_pkg = '';
+ $custnum = '';
}
-my($part_svc)=qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
+$part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
die "Unkonwn svcpart" unless $part_svc;
-SendHeaders(); # one guess.
-print <<END;
-<HTML>
- <HEAD>
- <TITLE>Domain View</TITLE>
- </HEAD>
- <BODY>
- <CENTER><H1>Domain View</H1>
- <BASEFONT SIZE=3>
-<CENTER>
-<A HREF="../view/cust_pkg.cgi?$pkgnum">View this package (#$pkgnum)</A> |
-<A HREF="../view/cust_main.cgi?$custnum">View this customer (#$custnum)</A> |
-<A HREF="../">Main menu</A></CENTER><BR>
- <FONT SIZE=+1>Service #$svcnum</FONT>
- </CENTER>
-END
-
-print "<HR>";
-print "Service: <B>", $part_svc->svc, "</B>";
-print "<HR>";
-
-print qq!Domain name <B>$domain</B>.!;
-print qq!<P><A HREF="http://rs.internic.net/cgi-bin/whois?do+$domain">View whois information.</A>!;
-
-print "<HR>";
-
- #formatting
- print <<END;
-
- </BODY>
-</HTML>
-END
+$domain = $svc_domain->domain;
+$p = popurl(2);
+print $cgi->header( '-expires' => 'now' ), header('Domain View', menubar(
+ ( ( $pkgnum || $custnum )
+ ? ( "View this package (#$pkgnum)" => "${p}view/cust_pkg.cgi?$pkgnum",
+ "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+ )
+ : ( "Cancel this (unaudited) account" =>
+ "${p}misc/cancel-unaudited.cgi?$svcnum" )
+ ),
+ "Main menu" => $p,
+)),
+ "Service #$svcnum",
+ "<BR>Service: <B>", $part_svc->svc, "</B>",
+ "<BR>Domain name: <B>$domain</B>.",
+ qq!<BR><BR><A HREF="http://209.133.38.12/step1.cgi?query=$domain">View whois information.</A>!,
+ '</BODY></HTML>',
+;