automate more of the initial data adding...
authorivan <ivan>
Thu, 16 Feb 2006 21:43:02 +0000 (21:43 +0000)
committerivan <ivan>
Thu, 16 Feb 2006 21:43:02 +0000 (21:43 +0000)
FS/FS/Setup.pm [new file with mode: 0644]
FS/bin/freeside-setup
bin/populate-msgcat [deleted file]
httemplate/docs/admin.html
httemplate/docs/install.html

diff --git a/FS/FS/Setup.pm b/FS/FS/Setup.pm
new file mode 100644 (file)
index 0000000..8e89be5
--- /dev/null
@@ -0,0 +1,422 @@
+package FS::Setup;
+
+use strict;
+use vars qw( @ISA @EXPORT_OK );
+use Exporter;
+#use Tie::DxHash;
+use Tie::IxHash;
+use FS::UID qw( dbh );
+use FS::Record;
+
+use FS::svc_domain;
+$FS::svc_domain::whois_hack = 1;
+$FS::svc_domain::whois_hack = 1;
+
+@ISA = qw( Exporter );
+@EXPORT_OK = qw( create_initial_data );
+
+=head1 NAME
+
+FS::Setup - Database setup
+
+=head1 SYNOPSIS
+
+  use FS::Setup;
+
+=head1 DESCRIPTION
+
+Currently this module simply provides a place to store common subroutines for
+database setup.
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item
+
+=cut
+
+sub create_initial_data {
+  my %opt = @_;
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  $FS::UID::AutoCommit = 0;
+
+  populate_locales();
+
+  #initial_data data
+  populate_initial_data(%opt);
+
+  populate_msgcat();
+  
+  if ( $oldAutoCommit ) {
+    dbh->commit or die dbh->errstr;
+  }
+
+}
+
+sub populate_locales {
+
+  use Locale::Country;
+  use Locale::SubCountry;
+  use FS::cust_main_county;
+
+  #cust_main_county
+  foreach my $country ( sort map uc($_), all_country_codes ) {
+  
+    my $subcountry = eval { new Locale::SubCountry($country) };
+    my @states = $subcountry ? $subcountry->all_codes : undef;
+  
+    if ( !scalar(@states) || ( scalar(@states)==1 && !defined($states[0]) ) ) {
+  
+      my $cust_main_county = new FS::cust_main_county({
+        'tax'   => 0,
+        'country' => $country,
+      });  
+      my $error = $cust_main_county->insert;
+      die $error if $error;
+  
+    } else {
+  
+      if ( $states[0] =~ /^(\d+|\w)$/ ) {
+        @states = map $subcountry->full_name($_), @states
+      }
+  
+      foreach my $state ( @states ) {
+  
+        my $cust_main_county = new FS::cust_main_county({
+          'state' => $state,
+          'tax'   => 0,
+          'country' => $country,
+        });  
+        my $error = $cust_main_county->insert;
+        die $error if $error;
+  
+      }
+    
+    }
+  }
+
+}
+
+sub populate_initial_data {
+  my %opt = @_;
+
+  my $data = initial_data(%opt);
+
+  foreach my $table ( keys %$data ) {
+
+    my $class = "FS::$table";
+    eval "use $class;";
+    die $@ if $@;
+
+    my @records = @{ $data->{$table} };
+
+    foreach my $record ( @records ) {
+      my $args = delete($record->{'_insert_args'}) || [];
+      my $object = $class->new( $record );
+      my $error = $object->insert( @$args );
+      die "error inserting record into $table: $error\n"
+        if $error;
+    }
+
+  }
+
+}
+
+sub initial_data {
+  my %opt = @_;
+
+  #tie my %hash, 'Tie::DxHash', 
+  tie my %hash, 'Tie::IxHash', 
+
+    #billing events
+    'part_bill_event' => [
+      { 'payby'     => 'CARD',
+        'event'     => 'Batch card',
+        'seconds'   => 0,
+        'eventcode' => '$cust_bill->batch_card();',
+        'weight'    => 40,
+        'plan'      => 'batch-card',
+      },
+      { 'payby'     => 'BILL',
+        'event'     => 'Send invoice',
+        'seconds'   => 0,
+        'eventcode' => '$cust_bill->send();',
+        'weight'    => 50,
+        'plan'      => 'send',
+      },
+      { 'payby'     => 'DCRD',
+        'event'     => 'Send invoice',
+        'seconds'   => 0,
+        'eventcode' => '$cust_bill->send();',
+        'weight'    => 50,
+        'plan'      => 'send',
+      },
+      { 'payby'     => 'DCHK',
+        'event'     => 'Send invoice',
+        'seconds'   => 0,
+        'eventcode' => '$cust_bill->send();',
+        'weight'    => 50,
+        'plan'      => 'send',
+      },
+    ],
+    
+    #you must create a service definition. An example of a service definition
+    #would be a dial-up account or a domain. First, it is necessary to create a
+    #domain definition. Click on View/Edit service definitions and Add a new
+    #service definition with Table svc_domain (and no modifiers).
+    'part_svc' => [
+      { 'svc'   => 'Domain',
+        'svcdb' => 'svc_domain',
+      }
+    ],
+
+    #Now that you have created your first service, you must create a package
+    #including this service which you can sell to customers. Zero, one, or many
+    #services are bundled into a package. Click on View/Edit package
+    #definitions and Add a new package definition which includes quantity 1 of
+    #the svc_domain service you created above.
+    'part_pkg' => [
+      { 'pkg'     => 'System Domain',
+        'comment' => '(NOT FOR CUSTOMERS)',
+        'freq'    => '0',
+        'plan'    => 'flat',
+        '_insert_args' => [
+          'pkg_svc'     => { 1 => 1 }, # XXX
+          'primary_svc' => 1, #XXX
+          'options'     => {
+            'setup_fee' => '0',
+            'recur_fee' => '0',
+          },
+        ],
+      },
+    ],
+
+    #After you create your first package, then you must define who is able to
+    #sell that package by creating an agent type. An example of an agent type
+    #would be an internal sales representitive which sells regular and
+    #promotional packages, as opposed to an external sales representitive
+    #which would only sell regular packages of services. Click on View/Edit
+    #agent types and Add a new agent type.
+    'agent_type' => [
+      { 'atype' => 'internal' },
+    ],
+
+    #Allow this agent type to sell the package you created above.
+    'type_pkgs' => [
+      { 'typenum' => 1, #XXX
+        'pkgpart' => 1, #XXX
+      },
+    ],
+
+    #After creating a new agent type, you must create an agent. Click on
+    #View/Edit agents and Add a new agent.
+    'agent' => [
+      { 'agent'   => 'Internal',
+        'typenum' => 1, # XXX
+      },
+    ],
+
+    #Set up at least one Advertising source. Advertising sources will help you
+    #keep track of how effective your advertising is, tracking where customers
+    #heard of your service offerings. You must create at least one advertising
+    #source. If you do not wish to use the referral functionality, simply
+    #create a single advertising source only. Click on View/Edit advertising
+    #sources and Add a new advertising source.
+    'part_referral' => [
+      { 'referral' => 'Internal', },
+    ],
+    
+    #Click on New Customer and create a new customer for your system accounts
+    #with billing type Complimentary. Leave the First package dropdown set to
+    #(none).
+    'cust_main' => [
+      { 'agentnum'  => 1, #XXX
+        'refnum'    => 1, #XXX
+        'first'     => 'System',
+        'last'      => 'Accounts',
+        'address1'  => '1234 System Lane',
+        'city'      => 'Systemtown',
+        'state'     => 'CA',
+        'zip'       => '54321',
+        'country'   => 'US',
+        'payby'     => 'COMP',
+        'payinfo'   => 'system', #or something
+        'paydate'   => '1/2037',
+      },
+    ],
+
+    #From the Customer View screen of the newly created customer, order the
+    #package you defined above.
+    'cust_pkg' => [
+      { 'custnum' => 1, #XXX
+        'pkgpart' => 1, #XXX
+      },
+    ],
+
+    #From the Package View screen of the newly created package, choose
+    #(Provision) to add the customer's service for this new package.
+    #Add your own domain.
+    'svc_domain' => [
+      { 'domain'  => $opt{'domain'},
+        'pkgnum'  => 1, #XXX
+        'svcpart' => 1, #XXX
+        'action'  => 'N', #pseudo-field
+      },
+    ],
+
+    #Go back to View/Edit service definitions on the main menu, and Add a new
+    #service definition with Table svc_acct. Select your domain in the domsvc
+    #Modifier. Set Fixed to define a service locked-in to this domain, or
+    #Default to define a service which may select from among this domain and
+    #the customer's domains.
+
+    #not yet....
+
+  #)
+  ;
+
+  \%hash;
+
+}
+
+sub populate_msgcat {
+
+  use FS::Record qw(qsearch);
+  use FS::msgcat;
+
+  foreach my $del_msgcat ( qsearch('msgcat', {}) ) {
+    my $error = $del_msgcat->delete;
+    die $error if $error;
+  }
+
+  my %messages = msgcat_messages();
+
+  foreach my $msgcode ( keys %messages ) {
+    foreach my $locale ( keys %{$messages{$msgcode}} ) {
+      my $msgcat = new FS::msgcat( {
+        'msgcode' => $msgcode,
+        'locale'  => $locale,
+        'msg'     => $messages{$msgcode}{$locale},
+      });
+      my $error = $msgcat->insert;
+      die $error if $error;
+    }
+  }
+
+}
+
+sub msgcat_messages {
+
+  #  'msgcode' => {
+  #    'en_US' => 'Message',
+  #  },
+
+  (
+
+    'passwords_dont_match' => {
+      'en_US' => "Passwords don't match",
+    },
+
+    'invalid_card' => {
+      'en_US' => 'Invalid credit card number',
+    },
+
+    'unknown_card_type' => {
+      'en_US' => 'Unknown card type',
+    },
+
+    'not_a' => {
+      'en_US' => 'Not a ',
+    },
+
+    'empty_password' => {
+      'en_US' => 'Empty password',
+    },
+
+    'no_access_number_selected' => {
+      'en_US' => 'No access number selected',
+    },
+
+    'illegal_text' => {
+      'en_US' => 'Illegal (text)',
+      #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in field',
+    },
+
+    'illegal_or_empty_text' => {
+      'en_US' => 'Illegal or empty (text)',
+      #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in required field',
+    },
+
+    'illegal_username' => {
+      'en_US' => 'Illegal username',
+    },
+
+    'illegal_password' => {
+      'en_US' => 'Illegal password (',
+    },
+
+    'illegal_password_characters' => {
+      'en_US' => ' characters)',
+    },
+
+    'username_in_use' => {
+      'en_US' => 'Username in use',
+    },
+
+    'illegal_email_invoice_address' => {
+      'en_US' => 'Illegal email invoice address',
+    },
+
+    'illegal_name' => {
+      'en_US' => 'Illegal (name)',
+      #'en_US' => 'Only letters, numbers, spaces and the following punctuation symbols are permitted: , . - \' in field',
+    },
+
+    'illegal_phone' => {
+      'en_US' => 'Illegal (phone)',
+      #'en_US' => '',
+    },
+
+    'illegal_zip' => {
+      'en_US' => 'Illegal (zip)',
+      #'en_US' => '',
+    },
+
+    'expired_card' => {
+      'en_US' => 'Expired card',
+    },
+
+    'daytime' => {
+      'en_US' => 'Day Phone',
+    },
+
+    'night' => {
+      'en_US' => 'Night Phone',
+    },
+
+    'svc_external-id' => {
+      'en_US' => 'External ID',
+    },
+
+    'svc_external-title' => {
+      'en_US' => 'Title',
+    },
+
+  );
+}
+
+=back
+
+=head1 BUGS
+
+Sure.
+
+=head1 SEE ALSO
+
+=cut
+
+1;
+
index a16e517..bff2bcc 100755 (executable)
@@ -4,23 +4,20 @@
 BEGIN { $FS::Schema::setup_hack = 1; }
 
 use strict;
-use vars qw($opt_s);
+use vars qw($opt_s $opt_d $opt_v);
 use Getopt::Std;
-use Locale::Country;
-use Locale::SubCountry;
 use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
 use FS::Schema qw( dbdef_dist reload_dbdef );
 use FS::Record;
-use FS::cust_main_county;
 #use FS::raddb;
-use FS::part_bill_event;
+use FS::Setup qw(create_initial_data);
 
 die "Not running uid freeside!" unless checkeuid();
 
 #my %attrib2db =
 #  map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib;
 
-getopts("s");
+getopts("svd:");
 my $user = shift or die &usage;
 getsecrets($user);
 
@@ -94,6 +91,7 @@ my $dbh = adminsuidsetup $user;
 $|=1;
 
 foreach my $statement ( $dbdef->sql($dbh) ) {
+  warn $statement if $statement =~ /TABLE cdr/;
   $dbh->do( $statement )
     or die "CREATE error: ". $dbh->errstr. "\ndoing statement: $statement";
 }
@@ -104,69 +102,14 @@ dbdef_create($dbh, $dbdef_file);
 delete $FS::Schema::dbdef_cache{$dbdef_file}; #force an actual reload
 reload_dbdef($dbdef_file);
 
-#cust_main_county
-foreach my $country ( sort map uc($_), all_country_codes ) {
+create_initial_data('domain' => $opt_d);
 
-  my $subcountry = eval { new Locale::SubCountry($country) };
-  my @states = $subcountry ? $subcountry->all_codes : undef;
-
-  if ( !scalar(@states) || ( scalar(@states) == 1 && !defined($states[0]) ) ) {
-
-    my $cust_main_county = new FS::cust_main_county({
-      'tax'   => 0,
-      'country' => $country,
-    });  
-    my $error = $cust_main_county->insert;
-    die $error if $error;
-
-  } else {
-
-    if ( $states[0] =~ /^(\d+|\w)$/ ) {
-      @states = map $subcountry->full_name($_), @states
-    }
-
-    foreach my $state ( @states ) {
-
-      my $cust_main_county = new FS::cust_main_county({
-        'state' => $state,
-        'tax'   => 0,
-        'country' => $country,
-      });  
-      my $error = $cust_main_county->insert;
-      die $error if $error;
-
-    }
-  
-  }
-}
-
-#billing events
-foreach my $aref ( 
-  #[ 'COMP', 'Comp invoice', '$cust_bill->comp();', 30, 'comp' ],
-  [ 'CARD', 'Batch card', '$cust_bill->batch_card();', 40, 'batch-card' ],
-  [ 'BILL', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
-  [ 'DCRD', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
-  [ 'DCHK', 'Send invoice', '$cust_bill->send();', 50, 'send' ],
-) {
-
-  my $part_bill_event = new FS::part_bill_event({
-    'payby' => $aref->[0],
-    'event' => $aref->[1],
-    'eventcode' => $aref->[2],
-    'seconds' => 0,
-    'weight' => $aref->[3],
-    'plan' => $aref->[4],
-  });
-  my($error);
-  $error=$part_bill_event->insert;
-  die $error if $error;
-
-}
+warn "Freeside database initialized - commiting transaction\n" if $opt_v;
 
 $dbh->commit or die $dbh->errstr;
 $dbh->disconnect or die $dbh->errstr;
 
-#print "Freeside database initialized sucessfully\n";
+warn "Database initialization committed sucessfully\n" if $opt_v;
 
 sub dbdef_create { # reverse engineer the schema from the DB and save to file
   my( $dbh, $file ) = @_;
@@ -175,7 +118,7 @@ sub dbdef_create { # reverse engineer the schema from the DB and save to file
 }
 
 sub usage {
-  die "Usage:\n  freeside-setup user\n"; 
+  die "Usage:\n  freeside-setup -d domain.name [ -v ] user\n"; 
 }
 
 1;
diff --git a/bin/populate-msgcat b/bin/populate-msgcat
deleted file mode 100755 (executable)
index adac92d..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/perl -Tw
-
-use strict;
-use FS::UID qw(adminsuidsetup);
-use FS::Record qw(qsearch);
-use FS::msgcat;
-
-my $user = shift or die &usage;
-adminsuidsetup $user;
-
-foreach my $del_msgcat ( qsearch('msgcat', {}) ) {
-  my $error = $del_msgcat->delete;
-  die $error if $error;
-}
-
-my %messages = messages();
-
-foreach my $msgcode ( keys %messages ) {
-  foreach my $locale ( keys %{$messages{$msgcode}} ) {
-    my $msgcat = new FS::msgcat( {
-      'msgcode' => $msgcode,
-      'locale'  => $locale,
-      'msg'     => $messages{$msgcode}{$locale},
-    });
-    my $error = $msgcat->insert;
-    die $error if $error;
-  }
-}
-
-#print "Message catalog initialized sucessfully\n";
-
-sub messages {
-
-  #  'msgcode' => {
-  #    'en_US' => 'Message',
-  #  },
-
-  (
-
-    'passwords_dont_match' => {
-      'en_US' => "Passwords don't match",
-    },
-
-    'invalid_card' => {
-      'en_US' => 'Invalid credit card number',
-    },
-
-    'unknown_card_type' => {
-      'en_US' => 'Unknown card type',
-    },
-
-    'not_a' => {
-      'en_US' => 'Not a ',
-    },
-
-    'empty_password' => {
-      'en_US' => 'Empty password',
-    },
-
-    'no_access_number_selected' => {
-      'en_US' => 'No access number selected',
-    },
-
-    'illegal_text' => {
-      'en_US' => 'Illegal (text)',
-      #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in field',
-    },
-
-    'illegal_or_empty_text' => {
-      'en_US' => 'Illegal or empty (text)',
-      #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in required field',
-    },
-
-    'illegal_username' => {
-      'en_US' => 'Illegal username',
-    },
-
-    'illegal_password' => {
-      'en_US' => 'Illegal password (',
-    },
-
-    'illegal_password_characters' => {
-      'en_US' => ' characters)',
-    },
-
-    'username_in_use' => {
-      'en_US' => 'Username in use',
-    },
-
-    'illegal_email_invoice_address' => {
-      'en_US' => 'Illegal email invoice address',
-    },
-
-    'illegal_name' => {
-      'en_US' => 'Illegal (name)',
-      #'en_US' => 'Only letters, numbers, spaces and the following punctuation symbols are permitted: , . - \' in field',
-    },
-
-    'illegal_phone' => {
-      'en_US' => 'Illegal (phone)',
-      #'en_US' => '',
-    },
-
-    'illegal_zip' => {
-      'en_US' => 'Illegal (zip)',
-      #'en_US' => '',
-    },
-
-    'expired_card' => {
-      'en_US' => 'Expired card',
-    },
-
-    'daytime' => {
-      'en_US' => 'Day Phone',
-    },
-
-    'night' => {
-      'en_US' => 'Night Phone',
-    },
-
-    'svc_external-id' => {
-      'en_US' => 'External ID',
-    },
-
-    'svc_external-title' => {
-      'en_US' => 'Title',
-    },
-
-  );
-}
-
-sub usage {
-  die "Usage:\n\n  populate-msgcat user\n";
-}
-
index 9ce259c..2aa9348 100755 (executable)
   /home/httpd/html, open https://your_host/freeside/. Replace
   "your_host" with the name or network address of your web server.
   <li>Select <u>Configuration</u> from the main menu and update your configuration values.
-  <li>Next you must create a service definition.  An example of a service
-  definition would be a dial-up account or a domain.  First, it is
-  necessary to create a domain definition.  Click on <u>View/Edit service
-  definitions</u> and <u>Add a new service definition</u> with <i>Table</i>
-  <b>svc_domain</b> (and no modifiers).
 
-  <li>Now that you have created your first service, you must create a package
-  including this service which you can sell to customers.  Zero, one, or many
-  services are bundled into a package.  Click on <u>View/Edit package
-  definitions</u> and <u>Add a new package definition</u> which includes
-  quantity <b>1</b> of the svc_domain service you created above.
-
-  <li>After you create your first package, then you must define who is
-  able to sell that package by creating an agent type.  An example of
-  an agent type would be an internal sales representitive which sells
-  regular and promotional packages, as opposed to an external sales
-  representitive which would only sell regular packages of services.  Click on
-  <u>View/Edit agent types</u> and <u>Add a new agent type</u>.  Allow this
-  agent type to sell the package you created above.
-
-  <li>After creating a new agent type, you must create an agent.  Click on
-  <u>View/Edit agents</u> and <u>Add a new agent</u>.
-
-  <li>Set up at least one Advertising source.  Advertising sources will help
-  you keep track of how effective your advertising is, tracking where customers
-  heard of your service offerings.  You must create at least one advertising 
-  source.  If you do not wish to use the referral functionality, simply create
-  a single advertising source only.  Click on <u>View/Edit advertising
-  sources</u> and <u>Add a new advertising source</u>.
-
-  <li>Click on <u>New Customer</u> and create a new customer for your system
-  accounts with billing type <b>Complimentary</b>.  Leave the <i>First
-  package</i> dropdown set to <b>(none)</b>.
-
-  <li>From the Customer View screen of the newly created customer, order the
-  package you defined above.
-
-  <li>From the Package View screen of the newly created package, choose
-  <u>(Provision)</u> to add the customer's service for this new package.
-
-  <li>Add your own domain.
-
-  <li>Go back to <u>View/Edit service definitions</u> on the main menu, and
+  <li>Go to <u>View/Edit service definitions</u> on the main menu, and
   <u>Add a new service definition</u> with <i>Table</i> <b>svc_acct</b>.
   Select your domain in the <b>domsvc</b> Modifier.  Set <b>Fixed</b> to define
   a service locked-in to this domain, or <b>Default</b> to define a service
@@ -69,7 +28,7 @@
 
   <li>If you are using Freeside to keep track of sales taxes, define tax
   information for your locales by clicking on the <u>View/Edit locales and tax
-  rates</b> on the main menu.
+  rates</u> on the main menu.
 
   <li>If you would like Freeside to notify your customers when their credit
   cards and other billing arrangements are about to expire, arrange for
index 1f80db1..0257275 100644 (file)
@@ -196,17 +196,10 @@ require valid-user
 <pre>$ su
 # <a href="man/bin/freeside-adduser.html">freeside-adduser</a> fs_queue
 # <a href="man/bin/freeside-adduser.html">freeside-adduser</a> fs_selfservice</pre>
-  <li>As the freeside UNIX user, run <tt>freeside-setup <b>username</b></tt> to create the database tables, passing the username of a Freeside user you created above:
+  <li>As the freeside UNIX user, run <tt>freeside-setup -d <b>domain.name</b> <b>username</b></tt> to create the database tables and initial data, passing the username of a Freeside user you created above:
 <pre>
 $ su freeside
-$ freeside-setup <b>username</b>
-</pre>
-  Alternately, use the -s option to enable shipping addresses: <tt>freeside-setup -s <b>username</b></tt>
-  <li>As the freeside UNIX user, run <tt>bin/populate-msgcat <b>username</b></tt> (in the untar'ed freeside directory) to populate the message catalog, passing the username of a Freeside user you created above:
-<pre>
-$ su freeside
-$ cd <b>/path/to/freeside/</b>
-$ bin/populate-msgcat <b>username</b>
+$ freeside-setup -d </b>example.com</b> <b>username</b>
 </pre>
   <li><tt>freeside-queued</tt> was installed with the Perl modules.  Start it now and ensure that is run upon system startup (Do this manually, or edit the top-level Makefile, replacing INIT_FILE with the appropriate location on your systemand QUEUED_USER with the username of a Freeside user you created above, and run <tt>make install-init</tt>)
   <li>Now proceed to the initial <a href="admin.html">administration</a> of your installation.