33b3465e02f6688afdd3898ae07d10b96be6c320
[freeside.git] / FS / bin / freeside-setup
1 #!/usr/bin/perl -Tw
2
3 #to delay loading dbdef until we're ready
4 BEGIN { $FS::Record::setup_hack = 1; }
5
6 use strict;
7 use vars qw($opt_s);
8 use Getopt::Std;
9 use Locale::Country;
10 use Locale::SubCountry;
11 use DBI;
12 use DBIx::DBSchema 0.21;
13 use DBIx::DBSchema::Table;
14 use DBIx::DBSchema::Column;
15 use DBIx::DBSchema::ColGroup::Unique;
16 use DBIx::DBSchema::ColGroup::Index;
17 use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
18 use FS::Record;
19 use FS::cust_main_county;
20 use FS::raddb;
21 use FS::part_bill_event;
22
23 die "Not running uid freeside!" unless checkeuid();
24
25 my %attrib2db =
26   map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib;
27
28 getopts("s");
29 my $user = shift or die &usage;
30 getsecrets($user);
31
32 #needs to match FS::Record
33 my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
34
35 ###
36
37 #print "\nEnter the maximum username length: ";
38 #my($username_len)=&getvalue;
39 my $username_len = 32; #usernamemax config file
40
41 #print "\n\n", <<END, ":";
42 #Freeside tracks the RADIUS User-Name, check attribute Password and
43 #reply attribute Framed-IP-Address for each user.  You can specify additional
44 #check and reply attributes (or you can add them later with the
45 #fs-radius-add-check and fs-radius-add-reply programs).
46 #
47 #First enter any additional RADIUS check attributes you need to track for each 
48 #user, separated by whitespace.
49 #END
50 #my @check_attributes = map { $attrib2db{lc($_)} or die "unknown attribute $_"; }
51 #                         split(" ",&getvalue);
52 #
53 #print "\n\n", <<END, ":";
54 #Now enter any additional reply attributes you need to track for each user,
55 #separated by whitespace.
56 #END
57 #my @attributes = map { $attrib2db{lc($_)} or die "unknown attribute $_"; }
58 #                   split(" ",&getvalue);
59 #
60 #print "\n\n", <<END, ":";
61 #Do you wish to enable the tracking of a second, separate shipping/service
62 #address?
63 #END
64 #my $ship = &_yesno;
65 #
66 #sub getvalue {
67 #  my($x)=scalar(<STDIN>);
68 #  chop $x;
69 #  $x;
70 #}
71 #
72 #sub _yesno {
73 #  print " [y/N]:";
74 #  my $x = scalar(<STDIN>);
75 #  $x =~ /^y/i;
76 #}
77
78 my @check_attributes = (); #add later
79 my @attributes = (); #add later
80 my $ship = $opt_s;
81
82 ###
83
84 my($char_d) = 80; #default maxlength for text fields
85
86 #my(@date_type)  = ( 'timestamp', '', ''     );
87 my(@date_type)  = ( 'int', 'NULL', ''     );
88 my(@perl_type) = ( 'text', 'NULL', ''  ); 
89 my @money_type = ( 'decimal',   '', '10,2' );
90
91 ###
92 # create a dbdef object from the old data structure
93 ###
94
95 my(%tables)=&tables_hash_hack;
96
97 #turn it into objects
98 my($dbdef) = new DBIx::DBSchema ( map {  
99   my(@columns);
100   while (@{$tables{$_}{'columns'}}) {
101     my($name,$type,$null,$length)=splice @{$tables{$_}{'columns'}}, 0, 4;
102     push @columns, new DBIx::DBSchema::Column ( $name,$type,$null,$length );
103   }
104   DBIx::DBSchema::Table->new(
105     $_,
106     $tables{$_}{'primary_key'},
107     DBIx::DBSchema::ColGroup::Unique->new($tables{$_}{'unique'}),
108     DBIx::DBSchema::ColGroup::Index->new($tables{$_}{'index'}),
109     @columns,
110   );
111 } (keys %tables) );
112
113 my $cust_main = $dbdef->table('cust_main');
114 unless ($ship) { #remove ship_ from cust_main
115   $cust_main->delcolumn($_) foreach ( grep /^ship_/, $cust_main->columns );
116 } else { #add indices
117   push @{$cust_main->index->lol_ref},
118     map { [ "ship_$_" ] } qw( last company daytime night fax );
119 }
120
121 #add radius attributes to svc_acct
122
123 my($svc_acct)=$dbdef->table('svc_acct');
124
125 my($attribute);
126 foreach $attribute (@attributes) {
127   $svc_acct->addcolumn ( new DBIx::DBSchema::Column (
128     'radius_'. $attribute,
129     'varchar',
130     'NULL',
131     $char_d,
132   ));
133 }
134
135 foreach $attribute (@check_attributes) {
136   $svc_acct->addcolumn( new DBIx::DBSchema::Column (
137     'rc_'. $attribute,
138     'varchar',
139     'NULL',
140     $char_d,
141   ));
142 }
143
144 #create history tables (false laziness w/create-history-tables)
145 foreach my $table ( grep { ! /^h_/ } $dbdef->tables ) {
146   my $tableobj = $dbdef->table($table)
147     or die "unknown table $table";
148
149   die "unique->lol_ref undefined for $table"
150     unless defined $tableobj->unique->lol_ref;
151   die "index->lol_ref undefined for $table"
152     unless defined $tableobj->index->lol_ref;
153
154   my $h_tableobj = DBIx::DBSchema::Table->new( {
155     name        => "h_$table",
156     primary_key => 'historynum',
157     unique      => DBIx::DBSchema::ColGroup::Unique->new( [] ),
158     'index'     => DBIx::DBSchema::ColGroup::Index->new( [
159                      @{$tableobj->unique->lol_ref},
160                      @{$tableobj->index->lol_ref}
161                    ] ),
162     columns     => [
163                      DBIx::DBSchema::Column->new( {
164                        'name'    => 'historynum',
165                        'type'    => 'serial',
166                        'null'    => 'NOT NULL',
167                        'length'  => '',
168                        'default' => '',
169                        'local'   => '',
170                      } ),
171                      DBIx::DBSchema::Column->new( {
172                        'name'    => 'history_date',
173                        'type'    => 'int',
174                        'null'    => 'NULL',
175                        'length'  => '',
176                        'default' => '',
177                        'local'   => '',
178                      } ),
179                      DBIx::DBSchema::Column->new( {
180                        'name'    => 'history_user',
181                        'type'    => 'varchar',
182                        'null'    => 'NOT NULL',
183                        'length'  => '80',
184                        'default' => '',
185                        'local'   => '',
186                      } ),
187                      DBIx::DBSchema::Column->new( {
188                        'name'    => 'history_action',
189                        'type'    => 'varchar',
190                        'null'    => 'NOT NULL',
191                        'length'  => '80',
192                        'default' => '',
193                        'local'   => '',
194                      } ),
195                      map {
196                        my $column = $tableobj->column($_);
197
198                        #clone so as to not disturb the original
199                        $column = DBIx::DBSchema::Column->new( {
200                          map { $_ => $column->$_() }
201                            qw( name type null length default local )
202                        } );
203
204                        $column->type('int')
205                          if $column->type eq 'serial';
206                        #$column->default('')
207                        #  if $column->default =~ /^nextval\(/i;
208                        #( my $local = $column->local ) =~ s/AUTO_INCREMENT//i;
209                        #$column->local($local);
210                        $column;
211                      } $tableobj->columns
212                    ],
213   } );
214   $dbdef->addtable($h_tableobj);
215 }
216
217 #important
218 $dbdef->save($dbdef_file);
219 &FS::Record::reload_dbdef($dbdef_file);
220
221 ###
222 # create 'em
223 ###
224
225 my($dbh)=adminsuidsetup $user;
226
227 #create tables
228 $|=1;
229
230 foreach my $statement ( $dbdef->sql($dbh) ) {
231   $dbh->do( $statement )
232     or die "CREATE error: ". $dbh->errstr. "\ndoing statement: $statement";
233 }
234
235 #cust_main_county
236 foreach my $country ( sort map uc($_), all_country_codes ) {
237
238   my $subcountry = eval { new Locale::SubCountry($country) };
239   my @states = $subcountry ? $subcountry->all_codes : undef;
240
241   if ( !scalar(@states) || ( scalar(@states) == 1 && !defined($states[0]) ) ) {
242
243     my $cust_main_county = new FS::cust_main_county({
244       'tax'   => 0,
245       'country' => $country,
246     });  
247     my $error = $cust_main_county->insert;
248     die $error if $error;
249
250   } else {
251
252     if ( $states[0] =~ /^(\d+|\w)$/ ) {
253       @states = map $subcountry->full_name($_), @states
254     }
255
256     foreach my $state ( @states ) {
257
258       my $cust_main_county = new FS::cust_main_county({
259         'state' => $state,
260         'tax'   => 0,
261         'country' => $country,
262       });  
263       my $error = $cust_main_county->insert;
264       die $error if $error;
265
266     }
267   
268   }
269 }
270
271 #billing events
272 foreach my $aref ( 
273   [ 'COMP', 'Comp invoice', '$cust_bill->comp();', 30, 'comp' ],
274   [ 'CARD', 'Batch card', '$cust_bill->batch_card();', 40, 'batch-card' ],
275   [ 'BILL', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
276   [ 'DCRD', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
277   [ 'DCHK', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
278 ) {
279
280   my $part_bill_event = new FS::part_bill_event({
281     'payby' => $aref->[0],
282     'event' => $aref->[1],
283     'eventcode' => $aref->[2],
284     'seconds' => 0,
285     'weight' => $aref->[3],
286     'plan' => $aref->[4],
287   });
288   my($error);
289   $error=$part_bill_event->insert;
290   die $error if $error;
291
292 }
293
294 $dbh->commit or die $dbh->errstr;
295 $dbh->disconnect or die $dbh->errstr;
296
297 #print "Freeside database initialized sucessfully\n";
298
299 sub usage {
300   die "Usage:\n  freeside-setup [ -s ] user\n"; 
301 }
302
303 ###
304 # Now it becomes an object.  much better.
305 ###
306 sub tables_hash_hack {
307
308   #note that s/(date|change)/_$1/; to avoid keyword conflict.
309   #put a kludge in FS::Record to catch this or? (pry need some date-handling
310   #stuff anyway also)
311
312   my(%tables)=( #yech.}
313
314     'agent' => {
315       'columns' => [
316         'agentnum', 'serial',            '',     '',
317         'agent',    'varchar',           '',     $char_d,
318         'typenum',  'int',            '',     '',
319         'freq',     'int',       'NULL', '',
320         'prog',     @perl_type,
321         'disabled',     'char', 'NULL', 1,
322         'username', 'varchar',       'NULL',     $char_d,
323         '_password','varchar',       'NULL',     $char_d,
324       ],
325       'primary_key' => 'agentnum',
326       'unique' => [],
327       'index' => [ ['typenum'], ['disabled'] ],
328     },
329
330     'agent_type' => {
331       'columns' => [
332         'typenum',   'serial',  '', '',
333         'atype',     'varchar', '', $char_d,
334       ],
335       'primary_key' => 'typenum',
336       'unique' => [],
337       'index' => [],
338     },
339
340     'type_pkgs' => {
341       'columns' => [
342         'typenum',   'int',  '', '',
343         'pkgpart',   'int',  '', '',
344       ],
345       'primary_key' => '',
346       'unique' => [ ['typenum', 'pkgpart'] ],
347       'index' => [ ['typenum'] ],
348     },
349
350     'cust_bill' => {
351       'columns' => [
352         'invnum',    'serial',  '', '',
353         'custnum',   'int',  '', '',
354         '_date',     @date_type,
355         'charged',   @money_type,
356         'printed',   'int',  '', '',
357         'closed',    'char', 'NULL', 1,
358       ],
359       'primary_key' => 'invnum',
360       'unique' => [],
361       'index' => [ ['custnum'], ['_date'] ],
362     },
363
364     'cust_bill_event' => {
365       'columns' => [
366         'eventnum',    'serial',  '', '',
367         'invnum',   'int',  '', '',
368         'eventpart',   'int',  '', '',
369         '_date',     @date_type,
370         'status', 'varchar', '', $char_d,
371         'statustext', 'text', 'NULL', '',
372       ],
373       'primary_key' => 'eventnum',
374       #no... there are retries now #'unique' => [ [ 'eventpart', 'invnum' ] ],
375       'unique' => [],
376       'index' => [ ['invnum'], ['status'] ],
377     },
378
379     'part_bill_event' => {
380       'columns' => [
381         'eventpart',    'serial',  '', '',
382         'payby',       'char',  '', 4,
383         'event',       'varchar',           '',     $char_d,
384         'eventcode',    @perl_type,
385         'seconds',     'int', 'NULL', '',
386         'weight',      'int', '', '',
387         'plan',       'varchar', 'NULL', $char_d,
388         'plandata',   'text', 'NULL', '',
389         'disabled',     'char', 'NULL', 1,
390       ],
391       'primary_key' => 'eventpart',
392       'unique' => [],
393       'index' => [ ['payby'], ['disabled'], ],
394     },
395
396     'cust_bill_pkg' => {
397       'columns' => [
398         'pkgnum',  'int', '', '',
399         'invnum',  'int', '', '',
400         'setup',   @money_type,
401         'recur',   @money_type,
402         'sdate',   @date_type,
403         'edate',   @date_type,
404         'itemdesc', 'varchar', 'NULL', $char_d,
405       ],
406       'primary_key' => '',
407       'unique' => [],
408       'index' => [ ['invnum'] ],
409     },
410
411     'cust_bill_pkg_detail' => {
412       'columns' => [
413         'detailnum', 'serial', '', '',
414         'pkgnum',  'int', '', '',
415         'invnum',  'int', '', '',
416         'detail',  'varchar', '', $char_d,
417       ],
418       'primary_key' => 'detailnum',
419       'unique' => [],
420       'index' => [ [ 'pkgnum', 'invnum' ] ],
421     },
422
423     'cust_credit' => {
424       'columns' => [
425         'crednum',  'serial', '', '',
426         'custnum',  'int', '', '',
427         '_date',    @date_type,
428         'amount',   @money_type,
429         'otaker',   'varchar', '', 32,
430         'reason',   'text', 'NULL', '',
431         'closed',    'char', 'NULL', 1,
432       ],
433       'primary_key' => 'crednum',
434       'unique' => [],
435       'index' => [ ['custnum'] ],
436     },
437
438     'cust_credit_bill' => {
439       'columns' => [
440         'creditbillnum', 'serial', '', '',
441         'crednum',  'int', '', '',
442         'invnum',  'int', '', '',
443         '_date',    @date_type,
444         'amount',   @money_type,
445       ],
446       'primary_key' => 'creditbillnum',
447       'unique' => [],
448       'index' => [ ['crednum'], ['invnum'] ],
449     },
450
451     'cust_main' => {
452       'columns' => [
453         'custnum',  'serial',  '',     '',
454         'agentnum', 'int',  '',     '',
455 #        'titlenum', 'int',  'NULL',   '',
456         'last',     'varchar', '',     $char_d,
457 #        'middle',   'varchar', 'NULL', $char_d,
458         'first',    'varchar', '',     $char_d,
459         'ss',       'varchar', 'NULL', 11,
460         'company',  'varchar', 'NULL', $char_d,
461         'address1', 'varchar', '',     $char_d,
462         'address2', 'varchar', 'NULL', $char_d,
463         'city',     'varchar', '',     $char_d,
464         'county',   'varchar', 'NULL', $char_d,
465         'state',    'varchar', 'NULL', $char_d,
466         'zip',      'varchar', '',     10,
467         'country',  'char', '',     2,
468         'daytime',  'varchar', 'NULL', 20,
469         'night',    'varchar', 'NULL', 20,
470         'fax',      'varchar', 'NULL', 12,
471         'ship_last',     'varchar', 'NULL', $char_d,
472 #        'ship_middle',   'varchar', 'NULL', $char_d,
473         'ship_first',    'varchar', 'NULL', $char_d,
474         'ship_company',  'varchar', 'NULL', $char_d,
475         'ship_address1', 'varchar', 'NULL', $char_d,
476         'ship_address2', 'varchar', 'NULL', $char_d,
477         'ship_city',     'varchar', 'NULL', $char_d,
478         'ship_county',   'varchar', 'NULL', $char_d,
479         'ship_state',    'varchar', 'NULL', $char_d,
480         'ship_zip',      'varchar', 'NULL', 10,
481         'ship_country',  'char', 'NULL', 2,
482         'ship_daytime',  'varchar', 'NULL', 20,
483         'ship_night',    'varchar', 'NULL', 20,
484         'ship_fax',      'varchar', 'NULL', 12,
485         'payby',    'char', '',     4,
486         'payinfo',  'varchar', 'NULL', $char_d,
487         'paycvv',   'varchar', 'NULL', 4,
488         #'paydate',  @date_type,
489         'paydate',  'varchar', 'NULL', 10,
490         'payname',  'varchar', 'NULL', $char_d,
491         'tax',      'char', 'NULL', 1,
492         'otaker',   'varchar', '',    32,
493         'refnum',   'int',  '',     '',
494         'referral_custnum', 'int',  'NULL', '',
495         'comments', 'text', 'NULL', '',
496       ],
497       'primary_key' => 'custnum',
498       'unique' => [],
499       #'index' => [ ['last'], ['company'] ],
500       'index' => [ ['last'], [ 'company' ], [ 'referral_custnum' ],
501                    [ 'daytime' ], [ 'night' ], [ 'fax' ],
502                  ],
503     },
504
505     'cust_main_invoice' => {
506       'columns' => [
507         'destnum',  'serial',  '',     '',
508         'custnum',  'int',  '',     '',
509         'dest',     'varchar', '',  $char_d,
510       ],
511       'primary_key' => 'destnum',
512       'unique' => [],
513       'index' => [ ['custnum'], ],
514     },
515
516     'cust_main_county' => { #county+state+country are checked off the
517                             #cust_main_county for validation and to provide
518                             # a tax rate.
519       'columns' => [
520         'taxnum',   'serial',   '',    '',
521         'state',    'varchar',  'NULL',    $char_d,
522         'county',   'varchar',  'NULL',    $char_d,
523         'country',  'char',  '', 2, 
524         'taxclass',   'varchar', 'NULL', $char_d,
525         'exempt_amount', @money_type,
526         'tax',      'real',  '',    '', #tax %
527         'taxname',  'varchar',  'NULL',    $char_d,
528         'setuptax',  'char', 'NULL', 1, # Y = setup tax exempt
529         'recurtax',  'char', 'NULL', 1, # Y = recur tax exempt
530       ],
531       'primary_key' => 'taxnum',
532       'unique' => [],
533   #    'unique' => [ ['taxnum'], ['state', 'county'] ],
534       'index' => [],
535     },
536
537     'cust_pay' => {
538       'columns' => [
539         'paynum',   'serial',    '',   '',
540         #now cust_bill_pay #'invnum',   'int',    '',   '',
541         'custnum',  'int',    '',   '',
542         'paid',     @money_type,
543         '_date',    @date_type,
544         'payby',    'char',   '',     4, # CARD/BILL/COMP, should be index into
545                                          # payment type table.
546         'payinfo',  'varchar',   'NULL', $char_d,  #see cust_main above
547         'paybatch', 'varchar',   'NULL', $char_d, #for auditing purposes.
548         'closed',    'char', 'NULL', 1,
549       ],
550       'primary_key' => 'paynum',
551       'unique' => [],
552       'index' => [ [ 'custnum' ], [ 'paybatch' ], [ 'payby' ], [ '_date' ] ],
553     },
554
555     'cust_bill_pay' => {
556       'columns' => [
557         'billpaynum', 'serial',     '',   '',
558         'invnum',  'int',     '',   '',
559         'paynum',  'int',     '',   '',
560         'amount',  @money_type,
561         '_date',   @date_type
562       ],
563       'primary_key' => 'billpaynum',
564       'unique' => [],
565       'index' => [ [ 'paynum' ], [ 'invnum' ] ],
566     },
567
568     'cust_pay_batch' => { #what's this used for again?  list of customers
569                           #in current CARD batch? (necessarily CARD?)
570       'columns' => [
571         'paybatchnum',   'serial',    '',   '',
572         'invnum',   'int',    '',   '',
573         'custnum',   'int',    '',   '',
574         'last',     'varchar', '',     $char_d,
575         'first',    'varchar', '',     $char_d,
576         'address1', 'varchar', '',     $char_d,
577         'address2', 'varchar', 'NULL', $char_d,
578         'city',     'varchar', '',     $char_d,
579         'state',    'varchar', 'NULL', $char_d,
580         'zip',      'varchar', '',     10,
581         'country',  'char', '',     2,
582 #        'trancode', 'int', '', '',
583         'cardnum',  'varchar', '',     16,
584         #'exp',      @date_type,
585         'exp',      'varchar', '',     11,
586         'payname',  'varchar', 'NULL', $char_d,
587         'amount',   @money_type,
588       ],
589       'primary_key' => 'paybatchnum',
590       'unique' => [],
591       'index' => [ ['invnum'], ['custnum'] ],
592     },
593
594     'cust_pkg' => {
595       'columns' => [
596         'pkgnum',    'serial',    '',   '',
597         'custnum',   'int',    '',   '',
598         'pkgpart',   'int',    '',   '',
599         'otaker',    'varchar', '', 32,
600         'setup',     @date_type,
601         'bill',      @date_type,
602         'last_bill', @date_type,
603         'susp',      @date_type,
604         'cancel',    @date_type,
605         'expire',    @date_type,
606         'manual_flag', 'char', 'NULL', 1,
607       ],
608       'primary_key' => 'pkgnum',
609       'unique' => [],
610       'index' => [ ['custnum'] ],
611     },
612
613     'cust_refund' => {
614       'columns' => [
615         'refundnum',    'serial',    '',   '',
616         #now cust_credit_refund #'crednum',      'int',    '',   '',
617         'custnum',  'int',    '',   '',
618         '_date',        @date_type,
619         'refund',       @money_type,
620         'otaker',       'varchar',   '',   32,
621         'reason',       'varchar',   '',   $char_d,
622         'payby',        'char',   '',     4, # CARD/BILL/COMP, should be index
623                                              # into payment type table.
624         'payinfo',      'varchar',   'NULL', $char_d,  #see cust_main above
625         'paybatch',     'varchar',   'NULL', $char_d,
626         'closed',    'char', 'NULL', 1,
627       ],
628       'primary_key' => 'refundnum',
629       'unique' => [],
630       'index' => [],
631     },
632
633     'cust_credit_refund' => {
634       'columns' => [
635         'creditrefundnum', 'serial',     '',   '',
636         'crednum',  'int',     '',   '',
637         'refundnum',  'int',     '',   '',
638         'amount',  @money_type,
639         '_date',   @date_type
640       ],
641       'primary_key' => 'creditrefundnum',
642       'unique' => [],
643       'index' => [ [ 'crednum', 'refundnum' ] ],
644     },
645
646
647     'cust_svc' => {
648       'columns' => [
649         'svcnum',    'serial',    '',   '',
650         'pkgnum',    'int',    'NULL',   '',
651         'svcpart',   'int',    '',   '',
652       ],
653       'primary_key' => 'svcnum',
654       'unique' => [],
655       'index' => [ ['svcnum'], ['pkgnum'], ['svcpart'] ],
656     },
657
658     'part_pkg' => {
659       'columns' => [
660         'pkgpart',    'serial',    '',   '',
661         'pkg',        'varchar',   '',   $char_d,
662         'comment',    'varchar',   '',   $char_d,
663         'setup',      @perl_type,
664         'freq',       'varchar',   '',   $char_d,  #billing frequency
665         'recur',      @perl_type,
666         'setuptax',  'char', 'NULL', 1,
667         'recurtax',  'char', 'NULL', 1,
668         'plan',       'varchar', 'NULL', $char_d,
669         'plandata',   'text', 'NULL', '',
670         'disabled',   'char', 'NULL', 1,
671         'taxclass',   'varchar', 'NULL', $char_d,
672       ],
673       'primary_key' => 'pkgpart',
674       'unique' => [],
675       'index' => [ [ 'disabled' ], ],
676     },
677
678 #    'part_title' => {
679 #      'columns' => [
680 #        'titlenum',   'int',    '',   '',
681 #        'title',      'varchar',   '',   $char_d,
682 #      ],
683 #      'primary_key' => 'titlenum',
684 #      'unique' => [ [] ],
685 #      'index' => [ [] ],
686 #    },
687
688     'pkg_svc' => {
689       'columns' => [
690         'pkgpart',    'int',    '',   '',
691         'svcpart',    'int',    '',   '',
692         'quantity',   'int',    '',   '',
693         'primary_svc','char', 'NULL',  1,
694       ],
695       'primary_key' => '',
696       'unique' => [ ['pkgpart', 'svcpart'] ],
697       'index' => [ ['pkgpart'] ],
698     },
699
700     'part_referral' => {
701       'columns' => [
702         'refnum',   'serial',    '',   '',
703         'referral', 'varchar',   '',   $char_d,
704         'disabled',     'char', 'NULL', 1,
705       ],
706       'primary_key' => 'refnum',
707       'unique' => [],
708       'index' => [ ['disabled'] ],
709     },
710
711     'part_svc' => {
712       'columns' => [
713         'svcpart',    'serial',    '',   '',
714         'svc',        'varchar',   '',   $char_d,
715         'svcdb',      'varchar',   '',   $char_d,
716         'disabled',   'char',  'NULL',   1,
717       ],
718       'primary_key' => 'svcpart',
719       'unique' => [],
720       'index' => [ [ 'disabled' ] ],
721     },
722
723     'part_svc_column' => {
724       'columns' => [
725         'columnnum',   'serial',         '', '',
726         'svcpart',     'int',         '', '',
727         'columnname',  'varchar',     '', 64,
728         'columnvalue', 'varchar', 'NULL', $char_d,
729         'columnflag',  'char',    'NULL', 1, 
730       ],
731       'primary_key' => 'columnnum',
732       'unique' => [ [ 'svcpart', 'columnname' ] ],
733       'index' => [ [ 'svcpart' ] ],
734     },
735
736     #(this should be renamed to part_pop)
737     'svc_acct_pop' => {
738       'columns' => [
739         'popnum',    'serial',    '',   '',
740         'city',      'varchar',   '',   $char_d,
741         'state',     'varchar',   '',   $char_d,
742         'ac',        'char',   '',   3,
743         'exch',      'char',   '',   3,
744         'loc',       'char',   'NULL',   4, #NULL for legacy purposes
745       ],
746       'primary_key' => 'popnum',
747       'unique' => [],
748       'index' => [ [ 'state' ] ],
749     },
750
751     'part_pop_local' => {
752       'columns' => [
753         'localnum',  'serial',     '',     '',
754         'popnum',    'int',     '',     '',
755         'city',      'varchar', 'NULL', $char_d,
756         'state',     'char',    'NULL', 2,
757         'npa',       'char',    '',     3,
758         'nxx',       'char',    '',     3,
759       ],
760       'primary_key' => 'localnum',
761       'unique' => [],
762       'index' => [ [ 'npa', 'nxx' ], [ 'popnum' ] ],
763     },
764
765     'svc_acct' => {
766       'columns' => [
767         'svcnum',    'int',    '',   '',
768         'username',  'varchar',   '',   $username_len, #unique (& remove dup code)
769         '_password', 'varchar',   '',   72, #13 for encryped pw's plus ' *SUSPENDED* (md5 passwords can be 34, blowfish 60)
770         'sec_phrase', 'varchar',  'NULL',   $char_d,
771         'popnum',    'int',    'NULL',   '',
772         'uid',       'int', 'NULL',   '',
773         'gid',       'int', 'NULL',   '',
774         'finger',    'varchar',   'NULL',   $char_d,
775         'dir',       'varchar',   'NULL',   $char_d,
776         'shell',     'varchar',   'NULL',   $char_d,
777         'quota',     'varchar',   'NULL',   $char_d,
778         'slipip',    'varchar',   'NULL',   15, #four TINYINTs, bah.
779         'seconds',   'int', 'NULL',   '', #uhhhh
780         'domsvc',    'int', '',   '',
781       ],
782       'primary_key' => 'svcnum',
783       #'unique' => [ [ 'username', 'domsvc' ] ],
784       'unique' => [],
785       'index' => [ ['username'], ['domsvc'] ],
786     },
787
788     #'svc_charge' => {
789     #  'columns' => [
790     #    'svcnum',    'int',    '',   '',
791     #    'amount',    @money_type,
792     #  ],
793     #  'primary_key' => 'svcnum',
794     #  'unique' => [ [] ],
795     #  'index' => [ [] ],
796     #},
797
798     'svc_domain' => {
799       'columns' => [
800         'svcnum',    'int',    '',   '',
801         'domain',    'varchar',    '',   $char_d,
802         'catchall',  'int', 'NULL',    '',
803       ],
804       'primary_key' => 'svcnum',
805       'unique' => [ ['domain'] ],
806       'index' => [],
807     },
808
809     'domain_record' => {
810       'columns' => [
811         'recnum',    'serial',     '',  '',
812         'svcnum',    'int',     '',  '',
813         #'reczone',   'varchar', '',  $char_d,
814         'reczone',   'varchar', '',  255,
815         'recaf',     'char',    '',  2,
816         'rectype',   'varchar',    '',  5,
817         #'recdata',   'varchar', '',  $char_d,
818         'recdata',   'varchar', '',  255,
819       ],
820       'primary_key' => 'recnum',
821       'unique'      => [],
822       'index'       => [ ['svcnum'] ],
823     },
824
825     'svc_forward' => {
826       'columns' => [
827         'svcnum',   'int',            '',   '',
828         'srcsvc',   'int',        'NULL',   '',
829         'src',      'varchar',    'NULL',  255,
830         'dstsvc',   'int',        'NULL',   '',
831         'dst',      'varchar',    'NULL',  255,
832       ],
833       'primary_key' => 'svcnum',
834       'unique'      => [],
835       'index'       => [ ['srcsvc'], ['dstsvc'] ],
836     },
837
838     'svc_www' => {
839       'columns' => [
840         'svcnum',   'int',    '',  '',
841         'recnum',   'int',    '',  '',
842         'usersvc',  'int',    '',  '',
843       ],
844       'primary_key' => 'svcnum',
845       'unique'      => [],
846       'index'       => [],
847     },
848
849     #'svc_wo' => {
850     #  'columns' => [
851     #    'svcnum',    'int',    '',   '',
852     #    'svcnum',    'int',    '',   '',
853     #    'svcnum',    'int',    '',   '',
854     #    'worker',    'varchar',   '',   $char_d,
855     #    '_date',     @date_type,
856     #  ],
857     #  'primary_key' => 'svcnum',
858     #  'unique' => [ [] ],
859     #  'index' => [ [] ],
860     #},
861
862     'prepay_credit' => {
863       'columns' => [
864         'prepaynum',   'serial',     '',   '',
865         'identifier',  'varchar', '', $char_d,
866         'amount',      @money_type,
867         'seconds',     'int',     'NULL', '',
868       ],
869       'primary_key' => 'prepaynum',
870       'unique'      => [ ['identifier'] ],
871       'index'       => [],
872     },
873
874     'port' => {
875       'columns' => [
876         'portnum',  'serial',     '',   '',
877         'ip',       'varchar', 'NULL', 15,
878         'nasport',  'int',     'NULL', '',
879         'nasnum',   'int',     '',   '',
880       ],
881       'primary_key' => 'portnum',
882       'unique'      => [],
883       'index'       => [],
884     },
885
886     'nas' => {
887       'columns' => [
888         'nasnum',   'serial',     '',    '',
889         'nas',      'varchar', '',    $char_d,
890         'nasip',    'varchar', '',    15,
891         'nasfqdn',  'varchar', '',    $char_d,
892         'last',     'int',     '',    '',
893       ],
894       'primary_key' => 'nasnum',
895       'unique'      => [ [ 'nas' ], [ 'nasip' ] ],
896       'index'       => [ [ 'last' ] ],
897     },
898
899     'session' => {
900       'columns' => [
901         'sessionnum', 'serial',       '',   '',
902         'portnum',    'int',       '',   '',
903         'svcnum',     'int',       '',   '',
904         'login',      @date_type,
905         'logout',     @date_type,
906       ],
907       'primary_key' => 'sessionnum',
908       'unique'      => [],
909       'index'       => [ [ 'portnum' ] ],
910     },
911
912     'queue' => {
913       'columns' => [
914         'jobnum', 'serial', '', '',
915         'job', 'text', '', '',
916         '_date', 'int', '', '',
917         'status', 'varchar', '', $char_d,
918         'statustext', 'text', 'NULL', '',
919         'svcnum', 'int', 'NULL', '',
920       ],
921       'primary_key' => 'jobnum',
922       'unique'      => [],
923       'index'       => [ [ 'svcnum' ], [ 'status' ] ],
924     },
925
926     'queue_arg' => {
927       'columns' => [
928         'argnum', 'serial', '', '',
929         'jobnum', 'int', '', '',
930         'arg', 'text', 'NULL', '',
931       ],
932       'primary_key' => 'argnum',
933       'unique'      => [],
934       'index'       => [ [ 'jobnum' ] ],
935     },
936
937     'queue_depend' => {
938       'columns' => [
939         'dependnum', 'serial', '', '',
940         'jobnum', 'int', '', '',
941         'depend_jobnum', 'int', '', '',
942       ],
943       'primary_key' => 'dependnum',
944       'unique'      => [],
945       'index'       => [ [ 'jobnum' ], [ 'depend_jobnum' ] ],
946     },
947
948     'export_svc' => {
949       'columns' => [
950         'exportsvcnum' => 'serial', '', '',
951         'exportnum'    => 'int', '', '',
952         'svcpart'      => 'int', '', '',
953       ],
954       'primary_key' => 'exportsvcnum',
955       'unique'      => [ [ 'exportnum', 'svcpart' ] ],
956       'index'       => [ [ 'exportnum' ], [ 'svcpart' ] ],
957     },
958
959     'part_export' => {
960       'columns' => [
961         'exportnum', 'serial', '', '',
962         #'svcpart',   'int', '', '',
963         'machine', 'varchar', '', $char_d,
964         'exporttype', 'varchar', '', $char_d,
965         'nodomain',     'char', 'NULL', 1,
966       ],
967       'primary_key' => 'exportnum',
968       'unique'      => [],
969       'index'       => [ [ 'machine' ], [ 'exporttype' ] ],
970     },
971
972     'part_export_option' => {
973       'columns' => [
974         'optionnum', 'serial', '', '',
975         'exportnum', 'int', '', '',
976         'optionname', 'varchar', '', $char_d,
977         'optionvalue', 'text', 'NULL', '',
978       ],
979       'primary_key' => 'optionnum',
980       'unique'      => [],
981       'index'       => [ [ 'exportnum' ], [ 'optionname' ] ],
982     },
983
984     'radius_usergroup' => {
985       'columns' => [
986         'usergroupnum', 'serial', '', '',
987         'svcnum',       'int', '', '',
988         'groupname',    'varchar', '', $char_d,
989       ],
990       'primary_key' => 'usergroupnum',
991       'unique'      => [],
992       'index'       => [ [ 'svcnum' ], [ 'groupname' ] ],
993     },
994
995     'msgcat' => {
996       'columns' => [
997         'msgnum', 'serial', '', '',
998         'msgcode', 'varchar', '', $char_d,
999         'locale', 'varchar', '', 16,
1000         'msg', 'text', '', '',
1001       ],
1002       'primary_key' => 'msgnum',
1003       'unique'      => [ [ 'msgcode', 'locale' ] ],
1004       'index'       => [],
1005     },
1006
1007     'cust_tax_exempt' => {
1008       'columns' => [
1009         'exemptnum', 'serial', '', '',
1010         'custnum',   'int', '', '',
1011         'taxnum',    'int', '', '',
1012         'year',      'int', '', '',
1013         'month',     'int', '', '',
1014         'amount',   @money_type,
1015       ],
1016       'primary_key' => 'exemptnum',
1017       'unique'      => [ [ 'custnum', 'taxnum', 'year', 'month' ] ],
1018       'index'       => [],
1019     },
1020
1021     'router' => {
1022       'columns' => [
1023         'routernum', 'serial', '', '',
1024         'routername', 'varchar', '', $char_d,
1025         'svcnum', 'int', 'NULL', '',
1026       ],
1027       'primary_key' => 'routernum',
1028       'unique'      => [],
1029       'index'       => [],
1030     },
1031
1032     'part_svc_router' => {
1033       'columns' => [
1034         'svcpart', 'int', '', '',
1035         'routernum', 'int', '', '',
1036       ],
1037       'primary_key' => '',
1038       'unique'      => [],
1039       'index'       => [],
1040     },
1041
1042     'addr_block' => {
1043       'columns' => [
1044         'blocknum', 'serial', '', '',
1045         'routernum', 'int', '', '',
1046         'ip_gateway', 'varchar', '', 15,
1047         'ip_netmask', 'int', '', '',
1048       ],
1049       'primary_key' => 'blocknum',
1050       'unique'      => [ [ 'blocknum', 'routernum' ] ],
1051       'index'       => [],
1052     },
1053
1054     'svc_broadband' => {
1055       'columns' => [
1056         'svcnum', 'int', '', '',
1057         'blocknum', 'int', '', '',
1058         'speed_up', 'int', '', '',
1059         'speed_down', 'int', '', '',
1060         'ip_addr', 'varchar', '', 15,
1061       ],
1062       'primary_key' => 'svcnum',
1063       'unique'      => [],
1064       'index'       => [],
1065     },
1066
1067     'part_virtual_field' => {
1068       'columns' => [
1069         'vfieldpart', 'int', '', '',
1070         'dbtable', 'varchar', '', 32,
1071         'name', 'varchar', '', 32,
1072         'check_block', 'text', 'NULL', '',
1073         'length', 'int', 'NULL', '',
1074         'list_source', 'text', 'NULL', '',
1075         'label', 'varchar', 'NULL', 80,
1076       ],
1077       'primary_key' => 'vfieldpart',
1078       'unique' => [],
1079       'index' => [],
1080     },
1081
1082     'virtual_field' => {
1083       'columns' => [
1084         'recnum', 'int', '', '',
1085         'vfieldpart', 'int', '', '',
1086         'value', 'varchar', '', 128,
1087       ],
1088       'primary_key' => '',
1089       'unique' => [ [ 'vfieldpart', 'recnum' ] ],
1090       'index' => [],
1091     },
1092
1093     'acct_snarf' => {
1094       'columns' => [
1095         'snarfnum',  'int', '', '',
1096         'svcnum',    'int', '', '',
1097         'machine',   'varchar', '', 255,
1098         'protocol',  'varchar', '', $char_d,
1099         'username',  'varchar', '', $char_d,
1100         '_password', 'varchar', '', $char_d,
1101       ],
1102       'primary_key' => 'snarfnum',
1103       'unique' => [],
1104       'index'  => [ [ 'svcnum' ] ],
1105     },
1106
1107     'svc_external' => {
1108       'columns' => [
1109         'svcnum', 'int', '', '',
1110         'id',     'int', '', '',
1111         'title',  'varchar', 'NULL', $char_d,
1112       ],
1113       'primary_key' => 'svcnum',
1114       'unique'      => [],
1115       'index'       => [],
1116     },
1117
1118     'cust_pay_refund' => {
1119       'columns' => [
1120         'payrefundnum', 'serial', '', '',
1121         'paynum',  'int', '', '',
1122         'refundnum',  'int', '', '',
1123         '_date',    @date_type,
1124         'amount',   @money_type,
1125       ],
1126       'primary_key' => 'payrefundnum',
1127       'unique' => [],
1128       'index' => [ ['paynum'], ['refundnum'] ],
1129     },
1130
1131
1132
1133   );
1134
1135   %tables;
1136
1137 }
1138