add menu items for credit card batching, debug last-minute changes to payby.pm, add...
[freeside.git] / FS / FS / Setup.pm
1 package FS::Setup;
2
3 use strict;
4 use vars qw( @ISA @EXPORT_OK );
5 use Exporter;
6 #use Tie::DxHash;
7 use Tie::IxHash;
8 use FS::UID qw( dbh );
9 use FS::Record;
10
11 use FS::svc_domain;
12 $FS::svc_domain::whois_hack = 1;
13 $FS::svc_domain::whois_hack = 1;
14
15 @ISA = qw( Exporter );
16 @EXPORT_OK = qw( create_initial_data );
17
18 =head1 NAME
19
20 FS::Setup - Database setup
21
22 =head1 SYNOPSIS
23
24   use FS::Setup;
25
26 =head1 DESCRIPTION
27
28 Currently this module simply provides a place to store common subroutines for
29 database setup.
30
31 =head1 SUBROUTINES
32
33 =over 4
34
35 =item
36
37 =cut
38
39 sub create_initial_data {
40   my %opt = @_;
41
42   my $oldAutoCommit = $FS::UID::AutoCommit;
43   local $FS::UID::AutoCommit = 0;
44   $FS::UID::AutoCommit = 0;
45
46   populate_locales();
47
48   #initial_data data
49   populate_initial_data(%opt);
50
51   populate_access();
52
53   populate_msgcat();
54   
55   if ( $oldAutoCommit ) {
56     dbh->commit or die dbh->errstr;
57   }
58
59 }
60
61 sub populate_locales {
62
63   use Locale::Country;
64   use Locale::SubCountry;
65   use FS::cust_main_county;
66
67   #cust_main_county
68   foreach my $country ( sort map uc($_), all_country_codes ) {
69   
70     my $subcountry = eval { new Locale::SubCountry($country) };
71     my @states = $subcountry ? $subcountry->all_codes : undef;
72   
73     if ( !scalar(@states) || ( scalar(@states)==1 && !defined($states[0]) ) ) {
74
75       _add_locale( 'country'=>$country );
76   
77     } else {
78   
79       if ( $states[0] =~ /^(\d+|\w)$/ ) {
80         @states = map $subcountry->full_name($_), @states
81       }
82   
83       foreach my $state ( @states ) {
84         _add_locale( 'country'=>$country, 'state'=>$state);
85       }
86     
87     }
88   }
89
90 }
91
92 sub populate_addl_locales {
93
94   my %addl = (
95     'US' => {
96       'FM' => 'Federated States of Micronesia',
97       'MH' => 'Federated States of Micronesia',
98       'PW' => 'Federated States of Micronesia',
99       'AA' => "Armed Forces Americas (except Canada)",
100       'AE' => "Armed Forces Europe / Canada / Middle East / Africa",
101       'AP' => "Armed Forces Pacific",
102     },
103   );
104
105   foreach my $country ( keys %addl ) {
106     foreach my $state ( keys %{ $addl{$country} } ) {
107       # $longname = $addl{$country}{$state};
108       _add_locale( 'country'=>$country, 'state'=>$state);
109     }
110   }
111
112 }
113
114 sub _add_locale {
115   my $cust_main_county = new FS::cust_main_county( { 'tax'=>0, @_ });  
116   my $error = $cust_main_county->insert;
117   die $error if $error;
118 }
119
120 sub populate_initial_data {
121   my %opt = @_;
122
123   my $data = initial_data(%opt);
124
125   foreach my $table ( keys %$data ) {
126
127     my $class = "FS::$table";
128     eval "use $class;";
129     die $@ if $@;
130
131     my @records = @{ $data->{$table} };
132
133     foreach my $record ( @records ) {
134       my $args = delete($record->{'_insert_args'}) || [];
135       my $object = $class->new( $record );
136       my $error = $object->insert( @$args );
137       die "error inserting record into $table: $error\n"
138         if $error;
139     }
140
141   }
142
143 }
144
145 sub initial_data {
146   my %opt = @_;
147
148   #tie my %hash, 'Tie::DxHash', 
149   tie my %hash, 'Tie::IxHash', 
150
151     #superuser group
152     'access_group' => [
153       { 'groupname' => 'Superuser' },
154     ],
155
156     #billing events
157     'part_bill_event' => [
158       { 'payby'     => 'CARD',
159         'event'     => 'Batch card',
160         'seconds'   => 0,
161         'eventcode' => '$cust_bill->batch_card(%options);',
162         'weight'    => 40,
163         'plan'      => 'batch-card',
164       },
165       { 'payby'     => 'BILL',
166         'event'     => 'Send invoice',
167         'seconds'   => 0,
168         'eventcode' => '$cust_bill->send();',
169         'weight'    => 50,
170         'plan'      => 'send',
171       },
172       { 'payby'     => 'DCRD',
173         'event'     => 'Send invoice',
174         'seconds'   => 0,
175         'eventcode' => '$cust_bill->send();',
176         'weight'    => 50,
177         'plan'      => 'send',
178       },
179       { 'payby'     => 'DCHK',
180         'event'     => 'Send invoice',
181         'seconds'   => 0,
182         'eventcode' => '$cust_bill->send();',
183         'weight'    => 50,
184         'plan'      => 'send',
185       },
186       { 'payby'     => 'DCLN',
187         'event'     => 'Suspend',
188         'seconds'   => 0,
189         'eventcode' => '$cust_bill->suspend();',
190         'weight'    => 40,
191         'plan'      => 'suspend',
192       },
193       #{ 'payby'     => 'DCLN',
194       #  'event'     => 'Retriable',
195       #  'seconds'   => 0,
196       #  'eventcode' => '$cust_bill_event->retriable();',
197       #  'weight'    => 60,
198       #  'plan'      => 'retriable',
199       #},
200     ],
201     
202     #you must create a service definition. An example of a service definition
203     #would be a dial-up account or a domain. First, it is necessary to create a
204     #domain definition. Click on View/Edit service definitions and Add a new
205     #service definition with Table svc_domain (and no modifiers).
206     'part_svc' => [
207       { 'svc'   => 'Domain',
208         'svcdb' => 'svc_domain',
209       }
210     ],
211
212     #Now that you have created your first service, you must create a package
213     #including this service which you can sell to customers. Zero, one, or many
214     #services are bundled into a package. Click on View/Edit package
215     #definitions and Add a new package definition which includes quantity 1 of
216     #the svc_domain service you created above.
217     'part_pkg' => [
218       { 'pkg'     => 'System Domain',
219         'comment' => '(NOT FOR CUSTOMERS)',
220         'freq'    => '0',
221         'plan'    => 'flat',
222         '_insert_args' => [
223           'pkg_svc'     => { 1 => 1 }, # XXX
224           'primary_svc' => 1, #XXX
225           'options'     => {
226             'setup_fee' => '0',
227             'recur_fee' => '0',
228           },
229         ],
230       },
231     ],
232
233     #After you create your first package, then you must define who is able to
234     #sell that package by creating an agent type. An example of an agent type
235     #would be an internal sales representitive which sells regular and
236     #promotional packages, as opposed to an external sales representitive
237     #which would only sell regular packages of services. Click on View/Edit
238     #agent types and Add a new agent type.
239     'agent_type' => [
240       { 'atype' => 'internal' },
241     ],
242
243     #Allow this agent type to sell the package you created above.
244     'type_pkgs' => [
245       { 'typenum' => 1, #XXX
246         'pkgpart' => 1, #XXX
247       },
248     ],
249
250     #After creating a new agent type, you must create an agent. Click on
251     #View/Edit agents and Add a new agent.
252     'agent' => [
253       { 'agent'   => 'Internal',
254         'typenum' => 1, # XXX
255       },
256     ],
257
258     #Set up at least one Advertising source. Advertising sources will help you
259     #keep track of how effective your advertising is, tracking where customers
260     #heard of your service offerings. You must create at least one advertising
261     #source. If you do not wish to use the referral functionality, simply
262     #create a single advertising source only. Click on View/Edit advertising
263     #sources and Add a new advertising source.
264     'part_referral' => [
265       { 'referral' => 'Internal', },
266     ],
267     
268     #Click on New Customer and create a new customer for your system accounts
269     #with billing type Complimentary. Leave the First package dropdown set to
270     #(none).
271     'cust_main' => [
272       { 'agentnum'  => 1, #XXX
273         'refnum'    => 1, #XXX
274         'first'     => 'System',
275         'last'      => 'Accounts',
276         'address1'  => '1234 System Lane',
277         'city'      => 'Systemtown',
278         'state'     => 'CA',
279         'zip'       => '54321',
280         'country'   => 'US',
281         'payby'     => 'COMP',
282         'payinfo'   => 'system', #or something
283         'paydate'   => '1/2037',
284       },
285     ],
286
287     #From the Customer View screen of the newly created customer, order the
288     #package you defined above.
289     'cust_pkg' => [
290       { 'custnum' => 1, #XXX
291         'pkgpart' => 1, #XXX
292       },
293     ],
294
295     #From the Package View screen of the newly created package, choose
296     #(Provision) to add the customer's service for this new package.
297     #Add your own domain.
298     'svc_domain' => [
299       { 'domain'  => $opt{'domain'},
300         'pkgnum'  => 1, #XXX
301         'svcpart' => 1, #XXX
302         'action'  => 'N', #pseudo-field
303       },
304     ],
305
306     #Go back to View/Edit service definitions on the main menu, and Add a new
307     #service definition with Table svc_acct. Select your domain in the domsvc
308     #Modifier. Set Fixed to define a service locked-in to this domain, or
309     #Default to define a service which may select from among this domain and
310     #the customer's domains.
311
312     #not yet....
313
314   #)
315   ;
316
317   \%hash;
318
319 }
320
321 sub populate_access {
322
323   use FS::AccessRight;
324   use FS::access_right;
325
326   foreach my $rightname ( FS::AccessRight->rights ) {
327     my $access_right = new FS::access_right {
328       'righttype'   => 'FS::access_group',
329       'rightobjnum' => 1, #$supergroup->groupnum,
330       'rightname'   => $rightname,
331     };
332     my $ar_error = $access_right->insert;
333     die $ar_error if $ar_error;
334   }
335
336   #foreach my $agent ( qsearch('agent', {} ) ) {
337     my $access_groupagent = new FS::access_groupagent {
338       'groupnum' => 1, #$supergroup->groupnum,
339       'agentnum' => 1, #$agent->agentnum,
340     };
341     my $aga_error = $access_groupagent->insert;
342     die $aga_error if $aga_error;
343   #}
344
345 }
346
347 sub populate_msgcat {
348
349   use FS::Record qw(qsearch);
350   use FS::msgcat;
351
352   foreach my $del_msgcat ( qsearch('msgcat', {}) ) {
353     my $error = $del_msgcat->delete;
354     die $error if $error;
355   }
356
357   my %messages = msgcat_messages();
358
359   foreach my $msgcode ( keys %messages ) {
360     foreach my $locale ( keys %{$messages{$msgcode}} ) {
361       my $msgcat = new FS::msgcat( {
362         'msgcode' => $msgcode,
363         'locale'  => $locale,
364         'msg'     => $messages{$msgcode}{$locale},
365       });
366       my $error = $msgcat->insert;
367       die $error if $error;
368     }
369   }
370
371 }
372
373 sub msgcat_messages {
374
375   #  'msgcode' => {
376   #    'en_US' => 'Message',
377   #  },
378
379   (
380
381     'passwords_dont_match' => {
382       'en_US' => "Passwords don't match",
383     },
384
385     'invalid_card' => {
386       'en_US' => 'Invalid credit card number',
387     },
388
389     'unknown_card_type' => {
390       'en_US' => 'Unknown card type',
391     },
392
393     'not_a' => {
394       'en_US' => 'Not a ',
395     },
396
397     'empty_password' => {
398       'en_US' => 'Empty password',
399     },
400
401     'no_access_number_selected' => {
402       'en_US' => 'No access number selected',
403     },
404
405     'illegal_text' => {
406       'en_US' => 'Illegal (text)',
407       #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in field',
408     },
409
410     'illegal_or_empty_text' => {
411       'en_US' => 'Illegal or empty (text)',
412       #'en_US' => 'Only letters, numbers, spaces, and the following punctuation symbols are permitted: ! @ # $ % & ( ) - + ; : \' " , . ? / in required field',
413     },
414
415     'illegal_username' => {
416       'en_US' => 'Illegal username',
417     },
418
419     'illegal_password' => {
420       'en_US' => 'Illegal password (',
421     },
422
423     'illegal_password_characters' => {
424       'en_US' => ' characters)',
425     },
426
427     'username_in_use' => {
428       'en_US' => 'Username in use',
429     },
430
431     'illegal_email_invoice_address' => {
432       'en_US' => 'Illegal email invoice address',
433     },
434
435     'illegal_name' => {
436       'en_US' => 'Illegal (name)',
437       #'en_US' => 'Only letters, numbers, spaces and the following punctuation symbols are permitted: , . - \' in field',
438     },
439
440     'illegal_phone' => {
441       'en_US' => 'Illegal (phone)',
442       #'en_US' => '',
443     },
444
445     'illegal_zip' => {
446       'en_US' => 'Illegal (zip)',
447       #'en_US' => '',
448     },
449
450     'expired_card' => {
451       'en_US' => 'Expired card',
452     },
453
454     'daytime' => {
455       'en_US' => 'Day Phone',
456     },
457
458     'night' => {
459       'en_US' => 'Night Phone',
460     },
461
462     'svc_external-id' => {
463       'en_US' => 'External ID',
464     },
465
466     'svc_external-title' => {
467       'en_US' => 'Title',
468     },
469
470   );
471 }
472
473 =back
474
475 =head1 BUGS
476
477 Sure.
478
479 =head1 SEE ALSO
480
481 =cut
482
483 1;
484