s/dbdef/DBIx::DBSchema/
[freeside.git] / bin / fs-setup
1 #!/usr/bin/perl -Tw
2 #
3 # $Id: fs-setup,v 1.36 2001-04-15 12:56:31 ivan Exp $
4 #
5 # ivan@sisd.com 97-nov-8,9
6 #
7 # agent_type and type_pkgs added.
8 # (index need to be declared, & primary keys shoudln't have mysql syntax)
9 # ivan@sisd.com 97-nov-13
10 #
11 # pulled modified version back out of register.cgi ivan@sisd.com 98-feb-21
12 #
13 # removed extraneous sample data ivan@sisd.com 98-mar-23
14 #
15 # gained the big hash from dbdef.pm, dbdef.pm usage rewrite ivan@sisd.com
16 # 98-apr-19 - 98-may-11 plus
17 #
18 # finished up ivan@sisd.com 98-jun-1
19 #
20 # part_svc fields are all forced NULL, not the opposite
21 # hmm: also are forced varchar($char_d) as fixed '0' for things like
22 # uid is Not Good.  will this break anything else?
23 # ivan@sisd.com 98-jun-29
24 #
25 # ss is 11 chars ivan@sisd.com 98-jul-20
26 #
27 # setup of arbitrary radius fields ivan@sisd.com 98-aug-9
28 #
29 # ouch, removed index on company name that wasn't supposed to be there
30 # ivan@sisd.com 98-sep-4
31 #
32 # fix radius attributes ivan@sisd.com 98-sep-27
33 #
34 # $Log: fs-setup,v $
35 # Revision 1.36  2001-04-15 12:56:31  ivan
36 # s/dbdef/DBIx::DBSchema/
37 #
38 # Revision 1.35  2001/04/15 09:36:43  ivan
39 # http://www.sisd.com/freeside/list-archive/msg01450.html
40 #
41 # Revision 1.34  2001/04/09 23:05:16  ivan
42 # Transactions Part I!!!
43 #
44 # Revision 1.33  2001/02/03 14:03:50  ivan
45 # time-based prepaid cards, session monitor.  woop!
46 #
47 # Revision 1.32  2000/12/04 00:13:02  ivan
48 # fix nas.last type
49 #
50 # Revision 1.31  2000/12/01 18:34:53  ivan
51 # another tyop
52 #
53 # Revision 1.30  2000/12/01 18:33:32  ivan
54 # tyop
55 #
56 # Revision 1.29  2000/11/07 15:00:37  ivan
57 # session monitor
58 #
59 # Revision 1.28  2000/10/30 10:47:26  ivan
60 # nas.last can't be defined NULL if indexed
61 #
62 # Revision 1.26  2000/07/06 08:57:27  ivan
63 # support for radius check attributes (except importing).  poorly documented.
64 #
65 # Revision 1.25  2000/06/29 12:00:49  ivan
66 # support for pre-encrypted md5 passwords.
67 #
68 # Revision 1.24  2000/03/02 07:44:07  ivan
69 # typo forgot closing '
70 #
71 # Revision 1.23  2000/02/03 05:16:52  ivan
72 # beginning of DNS and Apache support
73 #
74 # Revision 1.22  2000/01/31 05:22:23  ivan
75 # prepaid "internet cards"
76 #
77 # Revision 1.21  2000/01/30 06:03:26  ivan
78 # postgres 6.5 finally supports decimal(10,2)
79 #
80 # Revision 1.20  2000/01/28 22:53:33  ivan
81 # track full phone number
82 #
83 # Revision 1.19  1999/07/29 08:50:35  ivan
84 # wrong type for cust_pay_batch.exp
85 #
86 # Revision 1.18  1999/04/15 22:46:30  ivan
87 # TT isn't a state!
88 #
89 # Revision 1.17  1999/04/14 07:58:39  ivan
90 # export getsecrets from FS::UID instead of calling it explicitly
91 #
92 # Revision 1.16  1999/02/28 19:44:16  ivan
93 # constructors s/create/new/ pointed out by "Bao C. Ha" <bao@hacom.net>
94 #
95 # Revision 1.15  1999/02/27 21:06:21  ivan
96 # cust_main.paydate should be varchar(10), not @date_type ; problem reported
97 # by Ben Leibig <leibig@colorado.edu>
98 #
99 # Revision 1.14  1999/02/07 09:59:14  ivan
100 # more mod_perl fixes, and bugfixes Peter Wemm sent via email
101 #
102 # Revision 1.13  1999/02/04 06:09:23  ivan
103 # add AU provences
104 #
105 # Revision 1.12  1999/02/03 10:42:27  ivan
106 # *** empty log message ***
107 #
108 # Revision 1.11  1999/01/17 03:11:52  ivan
109 # remove preliminary completehost changes
110 #
111 # Revision 1.10  1998/12/16 06:05:38  ivan
112 # add table cust_main_invoice
113 #
114 # Revision 1.9  1998/12/15 04:36:29  ivan
115 # s/croak/die/; #oops
116 #
117 # Revision 1.8  1998/12/15 04:33:27  ivan
118 # dies if it isn't running as the freeside user
119 #
120 # Revision 1.7  1998/11/18 09:01:31  ivan
121 # i18n! i18n!
122 #
123 # Revision 1.6  1998/11/15 13:18:02  ivan
124 # remove debugging
125 #
126 # Revision 1.5  1998/11/15 09:43:03  ivan
127 # update for new config file syntax, new adminsuidsetup
128 #
129 # Revision 1.4  1998/10/22 15:51:23  ivan
130 # also varchar with no length specified - postgresql fix broke mysql.
131 #
132 # Revision 1.3  1998/10/22 15:46:28  ivan
133 # now smallint is illegal, so remove that too.
134 #
135
136 #to delay loading dbdef until we're ready
137 BEGIN { $FS::Record::setup_hack = 1; }
138
139 use strict;
140 use DBI;
141 use DBIx::DBSchema;
142 use DBIx::DBSchema::Table;
143 use DBIx::DBSchema::Column;
144 use DBIx::DBSchema::ColGroup::Unique;
145 use DBIx::DBSchema::ColGroup::Index;
146 use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
147 use FS::Record;
148 use FS::cust_main_county;
149
150 die "Not running uid freeside!" unless checkeuid();
151
152 my $user = shift or die &usage;
153 getsecrets($user);
154
155 #needs to match FS::Record
156 my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
157
158 ###
159
160 print "\nEnter the maximum username length: ";
161 my($username_len)=&getvalue;
162
163 print "\n\n", <<END, ":";
164 Freeside tracks the RADIUS attributes User-Name, check attribute Password and
165 reply attribute Framed-IP-Address for each user.  You can specify additional
166 check and reply attributes.  First enter any additional RADIUS check attributes
167 you need to track for each user, separated by whitespace.
168 END
169 my @check_attributes = map { s/\-/_/g; $_; } split(" ",&getvalue);
170
171 print "\n\n", <<END, ":";
172 Now enter any additional reply attributes you need to track for each user,
173 separated by whitespace.
174 END
175 my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue);
176
177 sub getvalue {
178   my($x)=scalar(<STDIN>);
179   chop $x;
180   $x;
181 }
182
183 ###
184
185 my($char_d) = 80; #default maxlength for text fields
186
187 #my(@date_type)  = ( 'timestamp', '', ''     );
188 my(@date_type)  = ( 'int', 'NULL', ''     );
189 my(@perl_type) = ( 'varchar', 'NULL', 255  ); 
190 my @money_type = ( 'decimal',   '', '10,2' );
191
192 ###
193 # create a dbdef object from the old data structure
194 ###
195
196 my(%tables)=&tables_hash_hack;
197
198 #turn it into objects
199 my($dbdef) = new DBIx::DBSchema ( map {  
200   my(@columns);
201   while (@{$tables{$_}{'columns'}}) {
202     my($name,$type,$null,$length)=splice @{$tables{$_}{'columns'}}, 0, 4;
203     push @columns, new DBIx::DBSchema::Column ( $name,$type,$null,$length );
204   }
205   DBIx::DBSchema::Table->new(
206     $_,
207     $tables{$_}{'primary_key'},
208     DBIx::DBSchema::ColGroup::Unique->new($tables{$_}{'unique'}),
209     DBIx::DBSchema::ColGroup::Index->new($tables{$_}{'index'}),
210     @columns,
211   );
212 } (keys %tables) );
213
214 #add radius attributes to svc_acct
215
216 my($svc_acct)=$dbdef->table('svc_acct');
217
218 my($attribute);
219 foreach $attribute (@attributes) {
220   $svc_acct->addcolumn ( new DBIx::DBSchema::Column (
221     'radius_'. $attribute,
222     'varchar',
223     'NULL',
224     $char_d,
225   ));
226 }
227
228 foreach $attribute (@check_attributes) {
229   $svc_acct->addcolumn( new DBIx::DBSchema::Column (
230     'rc_'. $attribute,
231     'varchar',
232     'NULL',
233     $char_d,
234   ));
235 }
236
237 #make part_svc table (but now as object)
238
239 my($part_svc)=$dbdef->table('part_svc');
240
241 #because of svc_acct_pop
242 #foreach (grep /^svc_/, $dbdef->tables) { 
243 #foreach (qw(svc_acct svc_acct_sm svc_charge svc_domain svc_wo)) {
244 foreach (qw(svc_acct svc_acct_sm svc_domain svc_www)) {
245   my($table)=$dbdef->table($_);
246   my($col);
247   foreach $col ( $table->columns ) {
248     next if $col =~ /^svcnum$/;
249     $part_svc->addcolumn( new DBIx::DBSchema::Column (
250       $table->name. '__' . $table->column($col)->name,
251       'varchar', #$table->column($col)->type, 
252       'NULL',
253       $char_d, #$table->column($col)->length,
254     ));
255     $part_svc->addcolumn ( new DBIx::DBSchema::Column (
256       $table->name. '__'. $table->column($col)->name . "_flag",
257       'char',
258       'NULL',
259       1,
260     ));
261   }
262 }
263
264 #important
265 $dbdef->save($dbdef_file);
266 &FS::Record::reload_dbdef($dbdef_file);
267
268 ###
269 # create 'em
270 ###
271
272 my($dbh)=adminsuidsetup $user;
273
274 #create tables
275 $|=1;
276
277 my @sql = $dbdef->sql($dbh);
278 foreach my $statement ( $dbdef->sql($dbh) ) {
279   $dbh->do( $statement )
280     or die "CREATE error: ",$dbh->errstr, "\ndoing statement: $statement";
281 }
282
283 #not really sample data (and shouldn't default to US)
284
285 #cust_main_county
286
287 #USPS state codes
288 foreach ( qw(
289 AL AK AS AZ AR CA CO CT DC DE FM FL GA GU HI ID IL IN IA KS KY LA
290 ME MH MD MA MI MN MS MO MT NC ND NE NH NJ NM NV NY MP OH OK OR PA PW PR RI 
291 SC SD TN TX UT VT VI VA WA WV WI WY AE AA AP
292 ) ) {
293   my($cust_main_county)=new FS::cust_main_county({
294     'state' => $_,
295     'tax'   => 0,
296     'country' => 'US',
297   });  
298   my($error);
299   $error=$cust_main_county->insert;
300   die $error if $error;
301 }
302
303 #AU "offical" state codes ala mark.williamson@ebbs.com.au (Mark Williamson)
304 foreach ( qw(
305 VIC NSW NT QLD TAS ACT WA SA
306 ) ) {
307   my($cust_main_county)=new FS::cust_main_county({
308     'state' => $_,
309     'tax'   => 0,
310     'country' => 'AU',
311   });  
312   my($error);
313   $error=$cust_main_county->insert;
314   die $error if $error;
315 }
316
317 #ISO 2-letter country codes (same as country TLDs) except US and AU
318 foreach ( qw(
319 AF AL DZ AS AD AO AI AQ AG AR AM AW AT AZ BS BH BD BB BY BE BZ BJ BM BT BO
320 BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CK CR CI
321 HR CU CY CZ DK DJ DM DO TP EC EG SV GQ ER EE ET FK FO FJ FI FR FX GF PF TF GA
322 GM GE DE GH GI GR GL GD GP GU GT GN GW GY HT HM HN HK HU IS IN ID IR IQ IE IL
323 IT JM JP JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV
324 ML MT MH MQ MR MU YT MX FM MD MC MN MS MA MZ MM NA NR NP NL AN NC NZ NI NE NG
325 NU NF MP NO OM PK PW PA PG PY PE PH PN PL PT PR QA RE RO RU RW KN LC VC WS SM
326 ST SA SN SC SL SG SK SI SB SO ZA GS ES LK SH PM SD SR SJ SZ SE CH SY TW TJ TZ
327 TH TG TK TO TT TN TR TM TC TV UG UA AE GB UM UY UZ VU VA VE VN VG VI WF EH
328 YE YU ZR ZM ZW
329 ) ) {
330   my($cust_main_county)=new FS::cust_main_county({
331     'tax'   => 0,
332     'country' => $_,
333   });  
334   my($error);
335   $error=$cust_main_county->insert;
336   die $error if $error;
337 }
338
339 $dbh->disconnect or die $dbh->errstr;
340
341 print "Freeside database initialized sucessfully\n";
342
343 sub usage {
344   die "Usage:\n  fs-setup user\n"; 
345 }
346
347 ###
348 # Now it becomes an object.  much better.
349 ###
350 sub tables_hash_hack {
351
352   #note that s/(date|change)/_$1/; to avoid keyword conflict.
353   #put a kludge in FS::Record to catch this or? (pry need some date-handling
354   #stuff anyway also)
355
356   my(%tables)=( #yech.}
357
358     'agent' => {
359       'columns' => [
360         'agentnum', 'int',            '',     '',
361         'agent',    'varchar',           '',     $char_d,
362         'typenum',  'int',            '',     '',
363         'freq',     'int',       'NULL', '',
364         'prog',     @perl_type,
365       ],
366       'primary_key' => 'agentnum',
367       'unique' => [ [] ],
368       'index' => [ ['typenum'] ],
369     },
370
371     'agent_type' => {
372       'columns' => [
373         'typenum',   'int',  '', '',
374         'atype',     'varchar', '', $char_d,
375       ],
376       'primary_key' => 'typenum',
377       'unique' => [ [] ],
378       'index' => [ [] ],
379     },
380
381     'type_pkgs' => {
382       'columns' => [
383         'typenum',   'int',  '', '',
384         'pkgpart',   'int',  '', '',
385       ],
386       'primary_key' => '',
387       'unique' => [ ['typenum', 'pkgpart'] ],
388       'index' => [ ['typenum'] ],
389     },
390
391     'cust_bill' => {
392       'columns' => [
393         'invnum',    'int',  '', '',
394         'custnum',   'int',  '', '',
395         '_date',     @date_type,
396         'charged',   @money_type,
397         'printed',   'int',  '', '',
398       ],
399       'primary_key' => 'invnum',
400       'unique' => [ [] ],
401       'index' => [ ['custnum'] ],
402     },
403
404     'cust_bill_pkg' => {
405       'columns' => [
406         'pkgnum',  'int', '', '',
407         'invnum',  'int', '', '',
408         'setup',   @money_type,
409         'recur',   @money_type,
410         'sdate',   @date_type,
411         'edate',   @date_type,
412       ],
413       'primary_key' => '',
414       'unique' => [ ['pkgnum', 'invnum'] ],
415       'index' => [ ['invnum'] ],
416     },
417
418     'cust_credit' => {
419       'columns' => [
420         'crednum',  'int', '', '',
421         'custnum',  'int', '', '',
422         '_date',    @date_type,
423         'amount',   @money_type,
424         'otaker',   'varchar', '', 8,
425         'reason',   'varchar', '', 255,
426       ],
427       'primary_key' => 'crednum',
428       'unique' => [ [] ],
429       'index' => [ ['custnum'] ],
430     },
431
432     'cust_main' => {
433       'columns' => [
434         'custnum',  'int',  '',     '',
435         'agentnum', 'int',  '',     '',
436 #        'titlenum', 'int',  'NULL',   '',
437         'last',     'varchar', '',     $char_d,
438 #        'middle',   'varchar', 'NULL', $char_d,
439         'first',    'varchar', '',     $char_d,
440         'ss',       'char', 'NULL', 11,
441         'company',  'varchar', 'NULL', $char_d,
442         'address1', 'varchar', '',     $char_d,
443         'address2', 'varchar', 'NULL', $char_d,
444         'city',     'varchar', '',     $char_d,
445         'county',   'varchar', 'NULL', $char_d,
446         'state',    'varchar', 'NULL', $char_d,
447         'zip',      'varchar', '',     10,
448         'country',  'char', '',     2,
449         'daytime',  'varchar', 'NULL', 20,
450         'night',    'varchar', 'NULL', 20,
451         'fax',      'varchar', 'NULL', 12,
452         'payby',    'char', '',     4,
453         'payinfo',  'varchar', 'NULL', 16,
454         #'paydate',  @date_type,
455         'paydate',  'varchar', 'NULL', 10,
456         'payname',  'varchar', 'NULL', $char_d,
457         'tax',      'char', 'NULL', 1,
458         'otaker',   'varchar', '',     8,
459         'refnum',   'int',  '',     '',
460       ],
461       'primary_key' => 'custnum',
462       'unique' => [ [] ],
463       #'index' => [ ['last'], ['company'] ],
464       'index' => [ ['last'], ],
465     },
466
467     'cust_main_invoice' => {
468       'columns' => [
469         'destnum',  'int',  '',     '',
470         'custnum',  'int',  '',     '',
471         'dest',     'varchar', '',  $char_d,
472       ],
473       'primary_key' => 'destnum',
474       'unique' => [ [] ],
475       'index' => [ ['custnum'], ],
476     },
477
478     'cust_main_county' => { #county+state+country are checked off the
479                             #cust_main_county for validation and to provide
480                             # a tax rate.
481       'columns' => [
482         'taxnum',   'int',   '',    '',
483         'state',    'varchar',  'NULL',    $char_d,
484         'county',   'varchar',  'NULL',    $char_d,
485         'country',  'char',  '', 2, 
486         'tax',      'real',  '',    '', #tax %
487       ],
488       'primary_key' => 'taxnum',
489       'unique' => [ [] ],
490   #    'unique' => [ ['taxnum'], ['state', 'county'] ],
491       'index' => [ [] ],
492     },
493
494     'cust_pay' => {
495       'columns' => [
496         'paynum',   'int',    '',   '',
497         'invnum',   'int',    '',   '',
498         'paid',     @money_type,
499         '_date',    @date_type,
500         'payby',    'char',   '',     4, # CARD/BILL/COMP, should be index into
501                                          # payment type table.
502         'payinfo',  'varchar',   'NULL', 16,  #see cust_main above
503         'paybatch', 'varchar',   'NULL', $char_d, #for auditing purposes.
504       ],
505       'primary_key' => 'paynum',
506       'unique' => [ [] ],
507       'index' => [ ['invnum'] ],
508     },
509
510     'cust_pay_batch' => { #what's this used for again?  list of customers
511                           #in current CARD batch? (necessarily CARD?)
512       'columns' => [
513         'invnum',   'int',    '',   '',
514         'custnum',   'int',    '',   '',
515         'last',     'varchar', '',     $char_d,
516         'first',    'varchar', '',     $char_d,
517         'address1', 'varchar', '',     $char_d,
518         'address2', 'varchar', 'NULL', $char_d,
519         'city',     'varchar', '',     $char_d,
520         'state',    'varchar', '',     $char_d,
521         'zip',      'varchar', '',     10,
522         'country',  'char', '',     2,
523         'trancode', 'int', '', '',
524         'cardnum',  'varchar', '',     16,
525         #'exp',      @date_type,
526         'exp',      'varchar', '',     11,
527         'payname',  'varchar', 'NULL', $char_d,
528         'amount',   @money_type,
529       ],
530       'primary_key' => '',
531       'unique' => [ [] ],
532       'index' => [ ['invnum'], ['custnum'] ],
533     },
534
535     'cust_pkg' => {
536       'columns' => [
537         'pkgnum',    'int',    '',   '',
538         'custnum',   'int',    '',   '',
539         'pkgpart',   'int',    '',   '',
540         'otaker',    'varchar', '', 8,
541         'setup',     @date_type,
542         'bill',      @date_type,
543         'susp',      @date_type,
544         'cancel',    @date_type,
545         'expire',    @date_type,
546       ],
547       'primary_key' => 'pkgnum',
548       'unique' => [ [] ],
549       'index' => [ ['custnum'] ],
550     },
551
552     'cust_refund' => {
553       'columns' => [
554         'refundnum',    'int',    '',   '',
555         'crednum',      'int',    '',   '',
556         '_date',        @date_type,
557         'refund',       @money_type,
558         'otaker',       'varchar',   '',   8,
559         'reason',       'varchar',   '',   $char_d,
560         'payby',        'char',   '',     4, # CARD/BILL/COMP, should be index
561                                              # into payment type table.
562         'payinfo',      'varchar',   'NULL', 16,  #see cust_main above
563       ],
564       'primary_key' => 'refundnum',
565       'unique' => [ [] ],
566       'index' => [ ['crednum'] ],
567     },
568
569     'cust_svc' => {
570       'columns' => [
571         'svcnum',    'int',    '',   '',
572         'pkgnum',    'int',    'NULL',   '',
573         'svcpart',   'int',    '',   '',
574       ],
575       'primary_key' => 'svcnum',
576       'unique' => [ [] ],
577       'index' => [ ['svcnum'], ['pkgnum'], ['svcpart'] ],
578     },
579
580     'part_pkg' => {
581       'columns' => [
582         'pkgpart',    'int',    '',   '',
583         'pkg',        'varchar',   '',   $char_d,
584         'comment',    'varchar',   '',   $char_d,
585         'setup',      @perl_type,
586         'freq',       'int', '', '',  #billing frequency (months)
587         'recur',      @perl_type,
588       ],
589       'primary_key' => 'pkgpart',
590       'unique' => [ [] ],
591       'index' => [ [] ],
592     },
593
594 #    'part_title' => {
595 #      'columns' => [
596 #        'titlenum',   'int',    '',   '',
597 #        'title',      'varchar',   '',   $char_d,
598 #      ],
599 #      'primary_key' => 'titlenum',
600 #      'unique' => [ [] ],
601 #      'index' => [ [] ],
602 #    },
603
604     'pkg_svc' => {
605       'columns' => [
606         'pkgpart',    'int',    '',   '',
607         'svcpart',    'int',    '',   '',
608         'quantity',   'int',    '',   '',
609       ],
610       'primary_key' => '',
611       'unique' => [ ['pkgpart', 'svcpart'] ],
612       'index' => [ ['pkgpart'] ],
613     },
614
615     'part_referral' => {
616       'columns' => [
617         'refnum',   'int',    '',   '',
618         'referral', 'varchar',   '',   $char_d,
619       ],
620       'primary_key' => 'refnum',
621       'unique' => [ [] ],
622       'index' => [ [] ],
623     },
624
625     'part_svc' => {
626       'columns' => [
627         'svcpart',    'int',    '',   '',
628         'svc',        'varchar',   '',   $char_d,
629         'svcdb',      'varchar',   '',   $char_d,
630       ],
631       'primary_key' => 'svcpart',
632       'unique' => [ [] ],
633       'index' => [ [] ],
634     },
635
636     #(this should be renamed to part_pop)
637     'svc_acct_pop' => {
638       'columns' => [
639         'popnum',    'int',    '',   '',
640         'city',      'varchar',   '',   $char_d,
641         'state',     'varchar',   '',   $char_d,
642         'ac',        'char',   '',   3,
643         'exch',      'char',   '',   3,
644         'loc',       'char',   'NULL',   4, #NULL for legacy purposes
645       ],
646       'primary_key' => 'popnum',
647       'unique' => [ [] ],
648       'index' => [ [] ],
649     },
650
651     'svc_acct' => {
652       'columns' => [
653         'svcnum',    'int',    '',   '',
654         'username',  'varchar',   '',   $username_len, #unique (& remove dup code)
655         '_password', 'varchar',   '',   50, #13 for encryped pw's plus ' *SUSPENDED* (mp5 passwords can be 34)
656         'popnum',    'int',    'NULL',   '',
657         'uid',       'int', 'NULL',   '',
658         'gid',       'int', 'NULL',   '',
659         'finger',    'varchar',   'NULL',   $char_d,
660         'dir',       'varchar',   'NULL',   $char_d,
661         'shell',     'varchar',   'NULL',   $char_d,
662         'quota',     'varchar',   'NULL',   $char_d,
663         'slipip',    'varchar',   'NULL',   15, #four TINYINTs, bah.
664         'seconds',   'int', 'NULL',   '', #uhhhh
665       ],
666       'primary_key' => 'svcnum',
667       'unique' => [ [] ],
668       'index' => [ ['username'] ],
669     },
670
671     'svc_acct_sm' => {
672       'columns' => [
673         'svcnum',    'int',    '',   '',
674         'domsvc',    'int',    '',   '',
675         'domuid',    'int', '',   '',
676         'domuser',   'varchar',   '',   $char_d,
677       ],
678       'primary_key' => 'svcnum',
679       'unique' => [ [] ],
680       'index' => [ ['domsvc'], ['domuid'] ], 
681     },
682
683     #'svc_charge' => {
684     #  'columns' => [
685     #    'svcnum',    'int',    '',   '',
686     #    'amount',    @money_type,
687     #  ],
688     #  'primary_key' => 'svcnum',
689     #  'unique' => [ [] ],
690     #  'index' => [ [] ],
691     #},
692
693     'svc_domain' => {
694       'columns' => [
695         'svcnum',    'int',    '',   '',
696         'domain',    'varchar',    '',   $char_d,
697       ],
698       'primary_key' => 'svcnum',
699       'unique' => [ ['domain'] ],
700       'index' => [ [] ],
701     },
702
703     'domain_record' => {
704       'columns' => [
705         'recnum',    'int',     '',  '',
706         'svcnum',    'int',     '',  '',
707         'reczone',   'varchar', '',  $char_d,
708         'recaf',     'char',    '',  2,
709         'rectype',   'char',    '',  5,
710         'recdata',   'varchar', '',  $char_d,
711       ],
712       'primary_key' => 'recnum',
713       'unique'      => [ [] ],
714       'index'       => [ ['svcnum'] ],
715     },
716
717     'svc_www' => {
718       'columns' => [
719         'svcnum',   'int',    '',  '',
720         'recnum',   'int',    '',  '',
721         'usersvc',  'int',    '',  '',
722       ],
723       'primary_key' => 'svcnum',
724       'unique'      => [ [] ],
725       'index'       => [ [] ],
726     },
727
728     #'svc_wo' => {
729     #  'columns' => [
730     #    'svcnum',    'int',    '',   '',
731     #    'svcnum',    'int',    '',   '',
732     #    'svcnum',    'int',    '',   '',
733     #    'worker',    'varchar',   '',   $char_d,
734     #    '_date',     @date_type,
735     #  ],
736     #  'primary_key' => 'svcnum',
737     #  'unique' => [ [] ],
738     #  'index' => [ [] ],
739     #},
740
741     'prepay_credit' => {
742       'columns' => [
743         'prepaynum',   'int',     '',   '',
744         'identifier',  'varchar', '', $char_d,
745         'amount',      @money_type,
746         'seconds',     'int',     'NULL', '',
747       ],
748       'primary_key' => 'prepaynum',
749       'unique'      => [ ['identifier'] ],
750       'index'       => [ [] ],
751     },
752
753     'port' => {
754       'columns' => [
755         'portnum',  'int',     '',   '',
756         'ip',       'varchar', 'NULL', 15,
757         'nasport',  'int',     'NULL', '',
758         'nasnum',   'int',     '',   '',
759       ],
760       'primary_key' => 'portnum',
761       'unique'      => [],
762       'index'       => [],
763     },
764
765     'nas' => {
766       'columns' => [
767         'nasnum',   'int',     '',    '',
768         'nas',      'varchar', '',    $char_d,
769         'nasip',    'varchar', '',    15,
770         'nasfqdn',  'varchar', '',    $char_d,
771         'last',     'int',     '',    '',
772       ],
773       'primary_key' => 'nasnum',
774       'unique'      => [ [ 'nas' ], [ 'nasip' ] ],
775       'index'       => [ [ 'last' ] ],
776     },
777
778     'session' => {
779       'columns' => [
780         'sessionnum', 'int',       '',   '',
781         'portnum',    'int',       '',   '',
782         'svcnum',     'int',       '',   '',
783         'login',      @date_type,
784         'logout',     @date_type,
785       ],
786       'primary_key' => 'sessionnum',
787       'unique'      => [],
788       'index'       => [ [ 'portnum' ] ],
789     },
790
791   );
792
793   %tables;
794
795 }
796