ecbb6e93285543cd5bdde82e9f9595785f9d4588
[freeside.git] / fs_selfservice / FS-SelfService / SelfService.pm
1 package FS::SelfService;
2
3 use strict;
4 use vars qw( $VERSION @ISA @EXPORT_OK $DEBUG
5              $skip_uid_check $dir $socket %autoload $tag );
6 use Exporter;
7 use Socket;
8 use FileHandle;
9 #use IO::Handle;
10 use IO::Select;
11 use Storable 2.09 qw(nstore_fd fd_retrieve);
12
13 $VERSION = '0.03';
14
15 @ISA = qw( Exporter );
16
17 $DEBUG = 0;
18
19 $dir = "/usr/local/freeside";
20 $socket =  "$dir/selfservice_socket";
21 $socket .= '.'.$tag if defined $tag && length($tag);
22
23 #maybe should ask ClientAPI for this list
24 %autoload = (
25   'passwd'                    => 'passwd/passwd',
26   'chfn'                      => 'passwd/passwd',
27   'chsh'                      => 'passwd/passwd',
28   'login_info'                => 'MyAccount/login_info',
29   'login_banner_image'        => 'MyAccount/login_banner_image',
30   'login'                     => 'MyAccount/login',
31   'logout'                    => 'MyAccount/logout',
32   'switch_acct'               => 'MyAccount/switch_acct',
33   'customer_info'             => 'MyAccount/customer_info',
34   'customer_info_short'       => 'MyAccount/customer_info_short',
35
36   'contact_passwd'            => 'MyAccount/contact/contact_passwd',
37   'list_contacts'             => 'MyAccount/contact/list_contacts',
38   'edit_contact'              => 'MyAccount/contact/edit_contact',
39   'delete_contact'            => 'MyAccount/contact/delete_contact',
40   'new_contact'               => 'MyAccount/contact/new_contact',
41
42   'billing_history'           => 'MyAccount/billing_history',
43   'edit_info'                 => 'MyAccount/edit_info',     #add to ss cgi!
44   'invoice'                   => 'MyAccount/invoice',
45   'invoice_pdf'               => 'MyAccount/invoice_pdf',
46   'legacy_invoice'            => 'MyAccount/legacy_invoice',
47   'legacy_invoice_pdf'        => 'MyAccount/legacy_invoice_pdf',
48   'invoice_logo'              => 'MyAccount/invoice_logo',
49   'list_invoices'             => 'MyAccount/list_invoices', #?
50   'cancel'                    => 'MyAccount/cancel',        #add to ss cgi!
51   'payment_info'              => 'MyAccount/payment_info',
52   'payment_info_renew_info'   => 'MyAccount/payment_info_renew_info',
53   'process_payment'           => 'MyAccount/process_payment',
54   'store_payment'             => 'MyAccount/store_payment',
55   'process_stored_payment'    => 'MyAccount/process_stored_payment',
56   'process_payment_order_pkg' => 'MyAccount/process_payment_order_pkg',
57   'process_payment_change_pkg' => 'MyAccount/process_payment_change_pkg',
58   'process_payment_order_renew' => 'MyAccount/process_payment_order_renew',
59   'process_prepay'            => 'MyAccount/process_prepay',
60   'realtime_collect'          => 'MyAccount/realtime_collect',
61   'list_pkgs'                 => 'MyAccount/list_pkgs',     #add to ss (added?)
62   'list_svcs'                 => 'MyAccount/list_svcs',     #add to ss (added?)
63   'list_svc_usage'            => 'MyAccount/list_svc_usage',   
64   'svc_status_html'           => 'MyAccount/svc_status_html',
65   'svc_status_hash'           => 'MyAccount/svc_status_hash',
66   'set_svc_status_hash'       => 'MyAccount/set_svc_status_hash',
67   'set_svc_status_listadd'    => 'MyAccount/set_svc_status_listadd',
68   'set_svc_status_listdel'    => 'MyAccount/set_svc_status_listdel',
69   'set_svc_status_vacationadd'=> 'MyAccount/set_svc_status_vacationadd',
70   'set_svc_status_vacationdel'=> 'MyAccount/set_svc_status_vacationdel',
71   'acct_forward_info'         => 'MyAccount/acct_forward_info',
72   'process_acct_forward'      => 'MyAccount/process_acct_forward',
73   'list_dsl_devices'          => 'MyAccount/list_dsl_devices',   
74   'add_dsl_device'            => 'MyAccount/add_dsl_device',   
75   'delete_dsl_device'         => 'MyAccount/delete_dsl_device',   
76   'port_graph'                => 'MyAccount/port_graph',   
77   'list_cdr_usage'            => 'MyAccount/list_cdr_usage',   
78   'list_support_usage'        => 'MyAccount/list_support_usage',   
79   'order_pkg'                 => 'MyAccount/order_pkg',     #add to ss cgi!
80   'change_pkg'                => 'MyAccount/change_pkg', 
81   'order_recharge'            => 'MyAccount/order_recharge',
82   'renew_info'                => 'MyAccount/renew_info',
83   'order_renew'               => 'MyAccount/order_renew',
84   'cancel_pkg'                => 'MyAccount/cancel_pkg',    #add to ss cgi!
85   'suspend_pkg'               => 'MyAccount/suspend_pkg',   #add to ss cgi!
86   'charge'                    => 'MyAccount/charge',        #?
87   'part_svc_info'             => 'MyAccount/part_svc_info',
88   'provision_acct'            => 'MyAccount/provision_acct',
89   'provision_phone'           => 'MyAccount/provision_phone',
90   'provision_pbx'             => 'MyAccount/provision_pbx',
91   'provision_external'        => 'MyAccount/provision_external',
92   'provision_forward'         => 'MyAccount/provision_forward',
93   'unprovision_svc'           => 'MyAccount/unprovision_svc',
94   'myaccount_passwd'          => 'MyAccount/myaccount_passwd',
95   'reset_passwd'              => 'MyAccount/reset_passwd',
96   'check_reset_passwd'        => 'MyAccount/check_reset_passwd',
97   'process_reset_passwd'      => 'MyAccount/process_reset_passwd',
98   'validate_passwd'           => 'MyAccount/validate_passwd',
99   'list_tickets'              => 'MyAccount/list_tickets',
100   'create_ticket'             => 'MyAccount/create_ticket',
101   'get_ticket'                => 'MyAccount/get_ticket',
102   'adjust_ticket_priority'    => 'MyAccount/adjust_ticket_priority',
103   'did_report'                => 'MyAccount/did_report',
104   'signup_info'               => 'Signup/signup_info',
105   'skin_info'                 => 'MyAccount/skin_info',
106   'access_info'               => 'MyAccount/access_info',
107   'domain_select_hash'        => 'Signup/domain_select_hash',  # expose?
108   'new_customer'              => 'Signup/new_customer',
109   'new_customer_minimal'      => 'Signup/new_customer_minimal',
110   'capture_payment'           => 'Signup/capture_payment',
111   #N/A 'clear_signup_cache'        => 'Signup/clear_cache',
112   'new_agent'                 => 'Agent/new_agent',
113   'agent_login'               => 'Agent/agent_login',
114   'agent_logout'              => 'Agent/agent_logout',
115   'agent_info'                => 'Agent/agent_info',
116   'agent_list_customers'      => 'Agent/agent_list_customers',
117   'check_username'            => 'Agent/check_username',
118   'suspend_username'          => 'Agent/suspend_username',
119   'unsuspend_username'        => 'Agent/unsuspend_username',
120   'mason_comp'                => 'MasonComponent/mason_comp',
121   'call_time'                 => 'PrepaidPhone/call_time',
122   'call_time_nanpa'           => 'PrepaidPhone/call_time_nanpa',
123   'phonenum_balance'          => 'PrepaidPhone/phonenum_balance',
124
125   'start_thirdparty'          => 'MyAccount/start_thirdparty',
126   'finish_thirdparty'         => 'MyAccount/finish_thirdparty',
127
128   'list_quotations'           => 'MyAccount/quotation/list_quotations',
129   'quotation_new'             => 'MyAccount/quotation/quotation_new',
130   'quotation_delete'          => 'MyAccount/quotation/quotation_delete',
131   'quotation_info'            => 'MyAccount/quotation/quotation_info',
132   'quotation_print'           => 'MyAccount/quotation/quotation_print',
133   'quotation_add_pkg'         => 'MyAccount/quotation/quotation_add_pkg',
134   'quotation_remove_pkg'      => 'MyAccount/quotation/quotation_remove_pkg',
135   'quotation_order'           => 'MyAccount/quotation/quotation_order',
136
137   'freesideinc_service'       => 'Freeside/freesideinc_service',
138
139 );
140 @EXPORT_OK = (
141   keys(%autoload),
142   qw( regionselector regionselector_hashref location_form
143       expselect popselector domainselector didselector
144     )
145 );
146
147 $ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin';
148 $ENV{'SHELL'} = '/bin/sh';
149 $ENV{'IFS'} = " \t\n";
150 $ENV{'CDPATH'} = '';
151 $ENV{'ENV'} = '';
152 $ENV{'BASH_ENV'} = '';
153
154 #you can add BEGIN { $FS::SelfService::skip_uid_check = 1; } 
155 #if you grant appropriate permissions to whatever user
156 my $freeside_uid = scalar(getpwnam('freeside'));
157 die "not running as the freeside user\n"
158   if $> != $freeside_uid && ! $skip_uid_check;
159
160 -e $dir or die "FATAL: $dir doesn't exist!";
161 -d $dir or die "FATAL: $dir isn't a directory!";
162 -r $dir or die "FATAL: Can't read $dir as freeside user!";
163 -x $dir or die "FATAL: $dir not searchable (executable) as freeside user!";
164
165 foreach my $autoload ( keys %autoload ) {
166
167   my $eval =
168   "sub $autoload { ". '
169                    my $param;
170                    if ( ref($_[0]) ) {
171                      $param = shift;
172                    } else {
173                      #warn scalar(@_). ": ". join(" / ", @_);
174                      $param = { @_ };
175                    }
176
177                    $param->{_packet} = \''. $autoload{$autoload}. '\';
178
179                    simple_packet($param);
180                  }';
181
182   eval $eval;
183   die $@ if $@;
184
185 }
186
187 sub simple_packet {
188   my $packet = shift;
189   warn "sending ". $packet->{_packet}. " to server"
190     if $DEBUG;
191   socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
192   connect(SOCK, sockaddr_un($socket)) or die "connect to $socket: $!";
193   nstore_fd($packet, \*SOCK) or die "can't send packet: $!";
194   SOCK->flush;
195
196   #shoudl trap: Magic number checking on storable file failed at blib/lib/Storable.pm (autosplit into blib/lib/auto/Storable/fd_retrieve.al) line 337, at /usr/local/share/perl/5.6.1/FS/SelfService.pm line 71
197
198   #block until there is a message on socket
199 #  my $w = new IO::Select;
200 #  $w->add(\*SOCK);
201 #  my @wait = $w->can_read;
202
203   warn "reading message from server"
204     if $DEBUG;
205
206   my $return = fd_retrieve(\*SOCK) or die "error reading result: $!";
207   die $return->{'_error'} if defined $return->{_error} && $return->{_error};
208
209   warn "returning message to client"
210     if $DEBUG;
211
212   $return;
213 }
214
215 =head1 NAME
216
217 FS::SelfService - Freeside self-service API
218
219 =head1 SYNOPSIS
220
221   # password and shell account changes
222   use FS::SelfService qw(passwd chfn chsh);
223
224   # "my account" functionality
225   use FS::SelfService qw( login customer_info invoice cancel payment_info process_payment );
226
227   #new-style login with an email address and password
228   # can also be used for svc_acct login, set $emailaddress to username@domain
229   my $rv = login ( { 'email'    => $emailaddress,
230                      'password' => $password,
231                    },
232                  );
233   if ( $rv->{'error'} ) {
234     #handle login error...
235   } else {
236     #successful login
237     $session_id = $rv->{'session_id'};
238   }
239
240   #classic svc_acct-based login with separate username and password
241   my $rv = login( { 'username' => $username,
242                     'domain'   => $domain,
243                     'password' => $password,
244                   }
245                 );
246   if ( $rv->{'error'} ) {
247     #handle login error...
248   } else {
249     #successful login
250     $session_id = $rv->{'session_id'};
251   }
252
253   #svc_phone login with phone number and PIN
254   my $rv = login( { 'username' => $phone_number,
255                     'domain'   => 'svc_phone',
256                     'password' => $pin,
257                   }
258                 );
259   if ( $rv->{'error'} ) {
260     #handle login error...
261   } else {
262     #successful login
263     $session_id = $rv->{'session_id'};
264   }
265
266   my $customer_info = customer_info( { 'session_id' => $session_id } );
267
268   #payment_info and process_payment are available in 1.5+ only
269   my $payment_info = payment_info( { 'session_id' => $session_id } );
270
271   #!!! process_payment example
272
273   #!!! list_pkgs example
274
275   #!!! order_pkg example
276
277   #quoting a package, then ordering after confirmation
278
279   my $rv = quotation_new({ 'session_id' => $session_id });
280   my $qnum = $rv->{quotationnum};
281   #  add packages to the quotation
282   $rv = quotation_add_pkg({ 'session_id'   => $session_id,
283                             'quotationnum' => $qnum,
284                             'pkgpart'      => $pkgpart,
285                             'quantity'     => $quantity, # defaults to 1
286                           });
287   #  repeat until all packages are added
288   #  view the pricing information
289   $rv = quotation_info({ 'session_id'   => $session_id,
290                          'quotationnum' => $qnum,
291                       });
292   print "Total setup charges: ".$rv->{total_setup}."\n".
293         "Total recurring charges: ".$rv->{total_recur}."\n";
294   #  quotation_info also provides a detailed breakdown of charges, in
295   #  $rv->{sections}.
296
297   #  ask customer for confirmation, then:
298   $rv = quotation_order({ 'session_id'   => $session_id,
299                           'quotationnum' => $qnum,
300                         });
301
302   #!!! cancel_pkg example
303
304   # signup functionality
305   use FS::SelfService qw( signup_info new_customer new_customer_minimal );
306
307   my $signup_info = signup_info;
308
309   $rv = new_customer( {
310                         'first'            => $first,
311                         'last'             => $last,
312                         'company'          => $company,
313                         'address1'         => $address1,
314                         'address2'         => $address2,
315                         'city'             => $city,
316                         'state'            => $state,
317                         'zip'              => $zip,
318                         'country'          => $country,
319                         'daytime'          => $daytime,
320                         'night'            => $night,
321                         'fax'              => $fax,
322                         'payby'            => $payby,
323                         'payinfo'          => $payinfo,
324                         'paycvv'           => $paycvv,
325                         'paystart_month'   => $paystart_month
326                         'paystart_year'    => $paystart_year,
327                         'payissue'         => $payissue,
328                         'payip'            => $payip
329                         'paydate'          => $paydate,
330                         'payname'          => $payname,
331                         'invoicing_list'   => $invoicing_list,
332                         'referral_custnum' => $referral_custnum,
333                         'agentnum'         => $agentnum,
334                         'pkgpart'          => $pkgpart,
335
336                         'username'         => $username,
337                         '_password'        => $password,
338                         'popnum'           => $popnum,
339                         #OR
340                         'countrycode'      => 1,
341                         'phonenum'         => $phonenum,
342                         'pin'              => $pin,
343                       }
344                     );
345   
346   my $error = $rv->{'error'};
347   if ( $error eq '_decline' ) {
348     print_decline();
349   } elsif ( $error ) {
350     reprint_signup();
351   } else {
352     print_success();
353   }
354
355 =head1 DESCRIPTION
356
357 Use this API to implement your own client "self-service" module.
358
359 If you just want to customize the look of the existing "self-service" module,
360 see XXXX instead.
361
362 =head1 PASSWORD, GECOS, SHELL CHANGING FUNCTIONS
363
364 =over 4
365
366 =item passwd
367
368 Changes the password for an existing user in svc_acct.  Takes a hash
369 reference with the following keys:
370
371 =over 4
372
373 =item username
374
375 Username of the account (required)
376
377 =item domain
378
379 Domain of the account (required)
380
381 =item old_password
382
383 Old password (required)
384
385 =item new_password
386  
387 New password (required)
388
389 =item new_gecos
390
391 New gecos
392
393 =item new_shell
394
395 New Shell
396
397 =back 
398
399 =item chfn
400
401 =item chsh
402
403 =back
404
405 =head1 "MY ACCOUNT" FUNCTIONS
406
407 =over 4
408
409 =item login HASHREF
410
411 Creates a user session.  Takes a hash reference as parameter with the
412 following keys:
413
414 =over 4
415
416 =item email
417
418 Email address (username@domain), instead of username and domain.  Required for
419 contact-based self-service login, can also be used for svc_acct-based login.
420
421 =item username
422
423 Username
424
425 =item domain
426
427 Domain
428
429 =item password
430
431 Password
432
433 =back
434
435 Returns a hash reference with the following keys:
436
437 =over 4
438
439 =item error
440
441 Empty on success, or an error message on errors.
442
443 =item session_id
444
445 Session identifier for successful logins
446
447 =back
448
449 =item customer_info HASHREF
450
451 Returns general customer information.
452
453 Takes a hash reference as parameter with a single key: B<session_id>
454
455 Returns a hash reference with the following keys:
456
457 =over 4
458
459 =item name
460
461 Customer name
462
463 =item balance
464
465 Balance owed
466
467 =item open
468
469 Array reference of hash references of open inoices.  Each hash reference has
470 the following keys: invnum, date, owed
471
472 =item small_custview
473
474 An HTML fragment containing shipping and billing addresses.
475
476 =item The following fields are also returned
477
478 first last company address1 address2 city county state zip country daytime night fax ship_first ship_last ship_company ship_address1 ship_address2 ship_city ship_state ship_zip ship_country ship_daytime ship_night ship_fax payby payinfo payname month year invoicing_list postal_invoicing
479
480 =back
481
482 =item edit_info HASHREF
483
484 Takes a hash reference as parameter with any of the following keys:
485
486 first last company address1 address2 city county state zip country daytime night fax ship_first ship_last ship_company ship_address1 ship_address2 ship_city ship_state ship_zip ship_country ship_daytime ship_night ship_fax payby payinfo paycvv payname month year invoicing_list postal_invoicing
487
488 If a field exists, the customer record is updated with the new value of that
489 field.  If a field does not exist, that field is not changed on the customer
490 record.
491
492 Returns a hash reference with a single key, B<error>, empty on success, or an
493 error message on errors
494
495 =item invoice HASHREF
496
497 Returns an invoice.  Takes a hash reference as parameter with two keys:
498 session_id and invnum
499
500 Returns a hash reference with the following keys:
501
502 =over 4
503
504 =item error
505
506 Empty on success, or an error message on errors
507
508 =item invnum
509
510 Invoice number
511
512 =item invoice_text
513
514 Invoice text
515
516 =back
517
518 =item list_invoices HASHREF
519
520 Returns a list of all customer invoices.  Takes a hash reference with a single
521 key, session_id.
522
523 Returns a hash reference with the following keys:
524
525 =over 4
526
527 =item error
528
529 Empty on success, or an error message on errors
530
531 =item invoices
532
533 Reference to array of hash references with the following keys:
534
535 =over 4
536
537 =item invnum
538
539 Invoice ID
540
541 =item _date
542
543 Invoice date, in UNIX epoch time
544
545 =back
546
547 =back
548
549 =item cancel HASHREF
550
551 Cancels this customer.
552
553 Takes a hash reference as parameter with a single key: B<session_id>
554
555 Returns a hash reference with a single key, B<error>, which is empty on
556 success or an error message on errors.
557
558 =item payment_info HASHREF
559
560 Returns information that may be useful in displaying a payment page.
561
562 Takes a hash reference as parameter with a single key: B<session_id>.
563
564 Returns a hash reference with the following keys:
565
566 =over 4
567
568 =item error
569
570 Empty on success, or an error message on errors
571
572 =item balance
573
574 Balance owed
575
576 =item payname
577
578 Exact name on credit card (CARD/DCRD)
579
580 =item address1
581
582 Address line one
583
584 =item address2
585
586 Address line two
587
588 =item city
589
590 City
591
592 =item state
593
594 State
595
596 =item zip
597
598 Zip or postal code
599
600 =item payby
601
602 Customer's current default payment type.
603
604 =item card_type
605
606 For CARD/DCRD payment types, the card type (Visa card, MasterCard, Discover card, American Express card, etc.)
607
608 =item payinfo
609
610 For CARD/DCRD payment types, the card number
611
612 =item month
613
614 For CARD/DCRD payment types, expiration month
615
616 =item year
617
618 For CARD/DCRD payment types, expiration year
619
620 =item cust_main_county
621
622 County/state/country data - array reference of hash references, each of which has the fields of a cust_main_county record (see L<FS::cust_main_county>).  Note these are not FS::cust_main_county objects, but hash references of columns and values.
623
624 =item states
625
626 Array reference of all states in the current default country.
627
628 =item card_types
629
630 Hash reference of card types; keys are card types, values are the exact strings
631 passed to the process_payment function
632
633 =cut
634
635 #this doesn't actually work yet
636 #
637 #=item paybatch
638 #
639 #Unique transaction identifier (prevents multiple charges), passed to the
640 #process_payment function
641
642 =back
643
644 =item process_payment HASHREF
645
646 Processes a payment and possible change of address or payment type.  Takes a
647 hash reference as parameter with the following keys:
648
649 =over 4
650
651 =item session_id
652
653 Session identifier
654
655 =item amount
656
657 Amount
658
659 =item save
660
661 If true, address and card information entered will be saved for subsequent
662 transactions.
663
664 =item auto
665
666 If true, future credit card payments will be done automatically (sets payby to
667 CARD).  If false, future credit card payments will be done on-demand (sets
668 payby to DCRD).  This option only has meaning if B<save> is set true.  
669
670 =item payname
671
672 Name on card
673
674 =item address1
675
676 Address line one
677
678 =item address2
679
680 Address line two
681
682 =item city
683
684 City
685
686 =item state
687
688 State
689
690 =item zip
691
692 Zip or postal code
693
694 =item country
695
696 Two-letter country code
697
698 =item payinfo
699
700 Card number
701
702 =item month
703
704 Card expiration month
705
706 =item year
707
708 Card expiration year
709
710 =cut
711
712 #this doesn't actually work yet
713 #
714 #=item paybatch
715 #
716 #Unique transaction identifier, returned from the payment_info function.
717 #Prevents multiple charges.
718
719 =back
720
721 Returns a hash reference with a single key, B<error>, empty on success, or an
722 error message on errors.
723
724 =item process_payment_order_pkg
725
726 Combines the B<process_payment> and B<order_pkg> functions in one step.  If the
727 payment processes sucessfully, the package is ordered.  Takes a hash reference
728 as parameter with the keys of both methods.
729
730 Returns a hash reference with a single key, B<error>, empty on success, or an
731 error message on errors.
732
733 =item process_payment_change_pkg
734
735 Combines the B<process_payment> and B<change_pkg> functions in one step.  If the
736 payment processes sucessfully, the package is ordered.  Takes a hash reference
737 as parameter with the keys of both methods.
738
739 Returns a hash reference with a single key, B<error>, empty on success, or an
740 error message on errors.
741
742
743 =item process_payment_order_renew
744
745 Combines the B<process_payment> and B<order_renew> functions in one step.  If
746 the payment processes sucessfully, the renewal is processed.  Takes a hash
747 reference as parameter with the keys of both methods.
748
749 Returns a hash reference with a single key, B<error>, empty on success, or an
750 error message on errors.
751
752 =item list_pkgs
753
754 Returns package information for this customer.  For more detail on services,
755 see L</list_svcs>.
756
757 Takes a hash reference as parameter with a single key: B<session_id>
758
759 Returns a hash reference containing customer package information.  The hash reference contains the following keys:
760
761 =over 4
762
763 =item custnum
764
765 Customer number
766
767 =item error
768
769 Empty on success, or an error message on errors.
770
771 =item cust_pkg HASHREF
772
773 Array reference of hash references, each of which has the fields of a cust_pkg
774 record (see L<FS::cust_pkg>) as well as the fields below.  Note these are not
775 the internal FS:: objects, but hash references of columns and values.
776
777 =over 4
778
779 =item part_pkg fields
780
781 All fields of part_pkg for this specific cust_pkg (be careful with this
782 information - it may reveal more about your available packages than you would
783 like users to know in aggregate) 
784
785 =cut
786
787 #XXX pare part_pkg fields down to a more secure subset
788
789 =item part_svc
790
791 An array of hash references indicating information on unprovisioned services
792 available for provisioning for this specific cust_pkg.  Each has the following
793 keys:
794
795 =over 4
796
797 =item part_svc fields
798
799 All fields of part_svc (be careful with this information - it may reveal more
800 about your available packages than you would like users to know in aggregate) 
801
802 =cut
803
804 #XXX pare part_svc fields down to a more secure subset
805
806 =back
807
808 =item cust_svc
809
810 An array of hash references indicating information on the customer services
811 already provisioned for this specific cust_pkg.  Each has the following keys:
812
813 =over 4
814
815 =item label
816
817 Array reference with three elements: The first element is the name of this service.  The second element is a meaningful user-specific identifier for the service (i.e. username, domain or mail alias).  The last element is the table name of this service.
818
819 =back
820
821 =item svcnum
822
823 Primary key for this service
824
825 =item svcpart
826
827 Service definition (see L<FS::part_svc>)
828
829 =item pkgnum
830
831 Customer package (see L<FS::cust_pkg>)
832
833 =item overlimit
834
835 Blank if the service is not over limit, or the date the service exceeded its usage limit (as a UNIX timestamp).
836
837 =back
838
839 =back
840
841 =item list_svcs
842
843 Returns service information for this customer.
844
845 Takes a hash reference as parameter with a single key: B<session_id>
846
847 Returns a hash reference containing customer package information.  The hash reference contains the following keys:
848
849 =over 4
850
851 =item custnum
852
853 Customer number
854
855 =item svcs
856
857 An array of hash references indicating information on all of this customer's
858 services.  Each has the following keys:
859
860 =over 4
861
862 =item svcnum
863
864 Primary key for this service
865
866 =item label
867
868 Name of this service
869
870 =item value
871
872 Meaningful user-specific identifier for the service (i.e. username, domain, or
873 mail alias).
874
875 =back
876
877 Account (svc_acct) services also have the following keys:
878
879 =over 4
880
881 =item username
882
883 Username
884
885 =item email
886
887 username@domain
888
889 =item seconds
890
891 Seconds remaining
892
893 =item upbytes
894
895 Upload bytes remaining
896
897 =item downbytes
898
899 Download bytes remaining
900
901 =item totalbytes
902
903 Total bytes remaining
904
905 =item recharge_amount
906
907 Cost of a recharge
908
909 =item recharge_seconds
910
911 Number of seconds gained by recharge
912
913 =item recharge_upbytes
914
915 Number of upload bytes gained by recharge
916
917 =item recharge_downbytes
918
919 Number of download bytes gained by recharge
920
921 =item recharge_totalbytes
922
923 Number of total bytes gained by recharge
924
925 =back
926
927 =back
928
929 =item order_pkg
930
931 Orders a package for this customer.
932
933 If signup_server-realtime is set, bills the new package, attemps to collect
934 payment and (for auto-payment customers) cancels the package if the payment is
935 declined.
936
937 Takes a hash reference as parameter with the following keys:
938
939 =over 4
940
941 =item session_id
942
943 Session identifier
944
945 =item pkgpart
946
947 Package to order (see L<FS::part_pkg>).
948
949 =item quantity
950
951 Quantity for this package order (default 1).
952
953 =item run_bill_events
954
955 If true, runs billing events for the customer after ordering and billing the
956 package (signup_server-realtime must be set).
957
958 =item locationnum
959
960 Optional locationnum for this package order, for existing locations.
961
962 Or, for new locations, pass the following fields: address1*, address2, city*,
963 county, state*, zip*, country.  (* = required in this case)
964
965 (None of this is required at all if you are just ordering a package
966 at the customer's existing default service location.)
967
968 =item address1
969
970 =item address2
971
972 =item city
973
974 =item county
975
976 =item state
977
978 =item zip
979
980 =item country
981
982 =item svcpart
983
984 Service to order (see L<FS::part_svc>).
985
986 Normally optional; required only to provision a non-svc_acct service, or if the
987 package definition does not contain one svc_acct service definition with
988 quantity 1 (it may contain others with quantity >1).  A svcpart of "none" can
989 also be specified to indicate that no initial service should be provisioned.
990
991 =back
992
993 Fields used when provisioning an svc_acct service:
994
995 =over 4
996
997 =item username
998
999 Username
1000
1001 =item _password
1002
1003 Password
1004
1005 =item sec_phrase
1006
1007 Optional security phrase
1008
1009 =item popnum
1010
1011 Optional Access number number
1012
1013 =back
1014
1015 Fields used when provisioning an svc_domain service:
1016
1017 =over 4
1018
1019 =item domain
1020
1021 Domain
1022
1023 =back
1024
1025 Fields used when provisioning an svc_phone service:
1026
1027 =over 4
1028
1029 =item phonenum
1030
1031 Phone number
1032
1033 =item pin
1034
1035 Voicemail PIN
1036
1037 =item sip_password
1038
1039 SIP password
1040
1041 =back
1042
1043 Fields used when provisioning an svc_external service:
1044
1045 =over 4
1046
1047 =item id
1048
1049 External numeric ID.
1050
1051 =item title
1052
1053 External text title.
1054
1055 =back
1056
1057 Fields used when provisioning an svc_pbx service:
1058
1059 =over 4
1060
1061 =item id
1062
1063 Numeric ID.
1064
1065 =item name
1066
1067 Text name.
1068
1069 =back
1070
1071 Returns a hash reference with a single key, B<error>, empty on success, or an
1072 error message on errors.  The special error '_decline' is returned for
1073 declined transactions.
1074
1075 =item change_pkg
1076
1077 Changes a package for this customer.
1078
1079 Takes a hash reference as parameter with the following keys:
1080
1081 =over 4
1082
1083 =item session_id
1084
1085 Session identifier
1086
1087 =item pkgnum
1088
1089 Existing customer package.
1090
1091 =item pkgpart
1092
1093 New package to order (see L<FS::part_pkg>).
1094
1095 =item quantity
1096
1097 Quantity for this package order (default 1).
1098
1099 =back
1100
1101 Returns a hash reference with the following keys:
1102
1103 =over 4
1104
1105 =item error
1106
1107 Empty on success, or an error message on errors.  
1108
1109 =item pkgnum
1110
1111 On success, the new pkgnum
1112
1113 =back
1114
1115
1116 =item renew_info
1117
1118 Provides useful info for early renewals.
1119
1120 Takes a hash reference as parameter with the following keys:
1121
1122 =over 4
1123
1124 =item session_id
1125
1126 Session identifier
1127
1128 =back
1129
1130 Returns a hash reference.  On errors, it contains a single key, B<error>, with
1131 the error message.  Otherwise, contains a single key, B<dates>, pointing to
1132 an array refernce of hash references.  Each hash reference contains the
1133 following keys:
1134
1135 =over 4
1136
1137 =item bill_date
1138
1139 (Future) Bill date.  Indicates a future date for which billing could be run.
1140 Specified as an integer UNIX timestamp.  Pass this value to the B<order_renew>
1141 function.
1142
1143 =item bill_date_pretty
1144
1145 (Future) Bill date as a human-readable string.  (Convenience for display;
1146 subject to change, so best not to parse for the date.)
1147
1148 =item amount
1149
1150 Base amount which will be charged if renewed early as of this date.
1151
1152 =item renew_date
1153
1154 Renewal date; i.e. even-futher future date at which the customer will be paid
1155 through if the early renewal is completed with the given B<bill-date>.
1156 Specified as an integer UNIX timestamp.
1157
1158 =item renew_date_pretty
1159
1160 Renewal date as a human-readable string.  (Convenience for display;
1161 subject to change, so best not to parse for the date.)
1162
1163 =item pkgnum
1164
1165 Package that will be renewed.
1166
1167 =item expire_date
1168
1169 Expiration date of the package that will be renewed.
1170
1171 =item expire_date_pretty
1172
1173 Expiration date of the package that will be renewed, as a human-readable
1174 string.  (Convenience for display; subject to change, so best not to parse for
1175 the date.)
1176
1177 =back
1178
1179 =item order_renew
1180
1181 Renews this customer early; i.e. runs billing for this customer in advance.
1182
1183 Takes a hash reference as parameter with the following keys:
1184
1185 =over 4
1186
1187 =item session_id
1188
1189 Session identifier
1190
1191 =item date
1192
1193 Integer date as returned by the B<renew_info> function, indicating the advance
1194 date for which to run billing.
1195
1196 =back
1197
1198 Returns a hash reference with a single key, B<error>, empty on success, or an
1199 error message on errors.
1200
1201 =item cancel_pkg
1202
1203 Cancels a package for this customer.
1204
1205 Takes a hash reference as parameter with the following keys:
1206
1207 =over 4
1208
1209 =item session_id
1210
1211 Session identifier
1212
1213 =item pkgpart
1214
1215 pkgpart of package to cancel
1216
1217 =item date
1218
1219 Optional date, for future cancellation (expiration) instead of immediate
1220 cancellation.  Specified as an integer UNIX timestamp ("epoch time").
1221
1222 =back
1223
1224 Returns a hash reference with a single key, B<error>, empty on success, or an
1225 error message on errors.
1226
1227 =item provision_acct 
1228
1229 Provisions an account (svc_acct).
1230
1231 Takes a hash reference as parameter with the following keys:
1232
1233 =over 4
1234
1235 =item session_id
1236
1237 Session identifier
1238
1239 =item pkgnum
1240
1241 pkgnum of package into which this service is provisioned
1242
1243 =item svcpart
1244
1245 svcpart or service definition to provision
1246
1247 =item username
1248
1249 =item domsvc
1250
1251 =item _password
1252
1253 =back
1254
1255 =item provision_phone
1256
1257 Provisions a phone number (svc_phone).
1258
1259 Takes a hash reference as parameter with the following keys:
1260
1261 =over 4
1262
1263 =item session_id
1264
1265 Session identifier
1266
1267 =item pkgnum
1268
1269 pkgnum of package into which this service is provisioned
1270
1271 =item svcpart
1272
1273 svcpart or service definition to provision
1274
1275 =item countrycode
1276
1277 =item phonenum
1278
1279 =item address1
1280
1281 =item address2
1282
1283 =item city
1284
1285 =item county
1286
1287 =item state
1288
1289 =item zip
1290
1291 =item country
1292
1293 E911 Address (optional)
1294
1295 =back
1296
1297 =item provision_pbx
1298
1299 Provisions a customer PBX (svc_pbx).
1300
1301 Takes a hash reference as parameter with the following keys:
1302
1303 =over 4
1304
1305 =item session_id
1306
1307 Session identifier
1308
1309 =item pkgnum
1310
1311 pkgnum of package into which this service is provisioned
1312
1313 =item svcpart
1314
1315 svcpart or service definition to provision
1316
1317 =item id
1318
1319 =item title
1320
1321 =item max_extensions
1322
1323 =item max_simultaneous
1324
1325 =item ip_addr
1326
1327 =back
1328
1329 =item provision_external
1330
1331 Provisions an external service (svc_external).
1332
1333 Takes a hash reference as parameter with the following keys:
1334
1335 =over 4
1336
1337 =item session_id
1338
1339 Session identifier
1340
1341 =item pkgnum
1342
1343 pkgnum of package into which this service is provisioned
1344
1345 =item svcpart
1346
1347 svcpart or service definition to provision
1348
1349 =item id
1350
1351 =item title
1352
1353 =back
1354
1355 =back
1356
1357 =head2 "MY ACCOUNT" CONTACT FUNCTIONS
1358
1359 =over 4
1360
1361 =item contact_passwd
1362
1363 Changes the password for the currently-logged in contact.
1364
1365 Takes a hash reference as parameter with the following keys:
1366
1367 =over 4
1368
1369 =item session_id
1370
1371 =item new_password
1372
1373 =back
1374
1375 Returns a hash reference with a single parameter, B<error>, which contains an
1376 error message, or empty on success.
1377
1378 =item list_contacts
1379
1380 Takes a hash reference as parameter with a single key, B<session_id>.
1381
1382 Returns a hash reference with two parameters: B<error>, which contains an error
1383 message, or empty on success, and B<contacts>, a list of contacts.
1384
1385 B<contacts> is an array reference of hash references (i.e. an array of structs,
1386  in XML-RPC).  Each hash reference (struct) has the following keys:
1387
1388 =over 4
1389
1390 =item contactnum
1391
1392 =item class
1393
1394 Contact class name (contact type).
1395
1396 =item first
1397
1398 First name
1399
1400 =item last
1401
1402 Last name
1403
1404 =item title
1405
1406 Position ("Director of Silly Walks"), NOT honorific ("Mr." or "Mrs.")
1407
1408 =item emailaddress
1409
1410 Comma-separated list of email addresses
1411
1412 =item comment
1413
1414 =item selfservice_access
1415
1416 Y when enabled
1417
1418 =back
1419
1420 =item edit_contact
1421
1422 Updates information for the currently-logged in contact, or (optionally) the
1423 specified contact.
1424
1425 Takes a hash reference as parameter with the following keys:
1426
1427 =over 4
1428
1429 =item session_id
1430
1431 =item contactnum
1432
1433 If already logged in as a contact, this is optional.
1434
1435 =item first
1436
1437 =item last
1438
1439 =item emailaddress
1440
1441 =back
1442
1443 Returns a hash reference with a single parameter, B<error>, which contains an
1444 error message, or empty on success.
1445
1446 =item new_contact
1447
1448 Creates a new contact.
1449
1450 Takes a hash reference as parameter with the following keys:
1451
1452 =over 4
1453
1454 =item session_id
1455
1456 =item first
1457
1458 =item last
1459
1460 =item emailaddress
1461
1462 =item classnum
1463
1464 Optional contact classnum (TODO: or name)
1465
1466 =item comment
1467
1468 =item selfservice_access
1469
1470 Y to enable self-service access
1471
1472 =item _password
1473
1474 =back
1475
1476 Returns a hash reference with a single parameter, B<error>, which contains an
1477 error message, or empty on success.
1478
1479 =item delete_contact
1480
1481 Deletes a contact.  (Note: Cannot at this time delete the currently-logged in
1482 contact.)
1483
1484 Takes a hash reference as parameter with the following keys:
1485
1486 =over 4
1487
1488 =item session_id
1489
1490 =item contactnum
1491
1492 =back
1493
1494 Returns a hash reference with a single parameter, B<error>, which contains an
1495 error message, or empty on success.
1496
1497 =back
1498
1499 =head2 "MY ACCOUNT" QUOTATION FUNCTIONS
1500
1501 All of these functions require the user to be logged in, and the 'session_id'
1502 key to be included in the argument hashref.`
1503
1504 =over 4
1505
1506 =item list_quotations HASHREF
1507
1508 Returns a hashref listing this customer's active self-service quotations.
1509 Contents are:
1510
1511 =over 4
1512
1513 =item quotations
1514
1515 an arrayref containing an element for each quotation.
1516
1517 =item quotationnum
1518
1519 the primary key
1520
1521 =item _date
1522
1523 the date it was started
1524
1525 =item num_pkgs
1526
1527 the number of packages
1528
1529 =item total_setup
1530
1531 the sum of setup fees
1532
1533 =item total_recur
1534
1535 the sum of recurring charges
1536
1537 =back
1538
1539 =item quotation_new HASHREF
1540
1541 Creates an empty quotation and returns a hashref containing 'quotationnum',
1542 the primary key of the new quotation.
1543
1544 =item quotation_delete HASHREF
1545
1546 Disables (does not really delete) a quotation. Takes the following arguments:
1547
1548 =over 4
1549
1550 =item session_id
1551
1552 =item quotationnum - the quotation to delete
1553
1554 =back
1555
1556 Returns 'error' => a string, which will be empty on success.
1557
1558 =item quotation_info HASHREF
1559
1560 Returns total and detailed pricing information on a quotation.
1561
1562 Takes the following arguments:
1563
1564 =over 4
1565
1566 =item session_id
1567
1568 =item quotationnum - the quotation to return
1569
1570 =back
1571
1572 Returns a hashref containing:
1573
1574 - total_setup, the total of setup fees (and their taxes)
1575 - total_recur, the total of all recurring charges (and their taxes)
1576 - sections, an arrayref containing an element for each quotation section.
1577   - description, a line of text describing the group of charges
1578   - subtotal, the total of charges in this group (if appropriate)
1579   - detail_items, an arrayref of line items
1580     - pkgnum, the reference number of the package
1581     - description, the package name (or tax name)
1582     - quantity
1583     - amount, the amount charged
1584     If the detail item represents a subtotal, it will instead contain:
1585     - total_item: description of the subtotal
1586     - total_amount: the subtotal amount
1587
1588
1589 =item quotation_print HASHREF
1590
1591 Renders the quotation as HTML or PDF. Takes the following arguments:
1592
1593 =over 4
1594
1595 =item session_id
1596
1597 =item quotationnum - the quotation to return
1598
1599 =item format - 'html' or 'pdf'
1600
1601 =back
1602
1603 Returns a hashref containing 'document', the contents of the file.
1604
1605 =item quotation_add_pkg HASHREF
1606
1607 Adds a package to a quotation. Takes the following arguments:
1608
1609 =over 4
1610
1611 =item session_id
1612
1613 =item pkgpart - the package to add
1614
1615 =item quotationnum - the quotation to add it to
1616
1617 =item quantity - the package quantity (defaults to 1)
1618
1619 =item address1, address2, city, state, zip, country - address fields to set
1620 the service location
1621
1622 =back
1623
1624 Returns 'error' => a string, which will be empty on success.
1625
1626 =item quotation_remove_pkg HASHREF
1627
1628 Removes a package from a quotation. Takes the following arguments:
1629
1630 =over 4
1631
1632 =item session_id
1633
1634 =item pkgnum - the primary key (quotationpkgnum) of the package to remove
1635
1636 =item quotationnum - the quotation to remove it from
1637
1638 =back
1639
1640 Returns 'error' => a string, which will be empty on success.
1641
1642 =item quotation_order HASHREF
1643
1644 Converts the packages in a quotation into real packages. Takes the following
1645 arguments:
1646
1647 Takes the following arguments:
1648
1649 =over 4
1650
1651 =item session_id
1652
1653 =item quotationnum - the quotation to order
1654
1655 =back
1656
1657 =back
1658
1659 =head1 SIGNUP FUNCTIONS
1660
1661 =over 4
1662
1663 =item signup_info HASHREF
1664
1665 Takes a hash reference as parameter with the following keys:
1666
1667 =over 4
1668
1669 =item session_id - Optional agent/reseller interface session
1670
1671 =back
1672
1673 Returns a hash reference containing information that may be useful in
1674 displaying a signup page.  The hash reference contains the following keys:
1675
1676 =over 4
1677
1678 =item cust_main_county
1679
1680 County/state/country data - array reference of hash references, each of which has the fields of a cust_main_county record (see L<FS::cust_main_county>).  Note these are not FS::cust_main_county objects, but hash references of columns and values.
1681
1682 =item part_pkg
1683
1684 Available packages - array reference of hash references, each of which has the fields of a part_pkg record (see L<FS::part_pkg>).  Each hash reference also has an additional 'payby' field containing an array reference of acceptable payment types specific to this package (see below and L<FS::part_pkg/payby>).  Note these are not FS::part_pkg objects, but hash references of columns and values.  Requires the 'signup_server-default_agentnum' configuration value to be set, or
1685 an agentnum specified explicitly via reseller interface session_id in the
1686 options.
1687
1688 =item agent
1689
1690 Array reference of hash references, each of which has the fields of an agent record (see L<FS::agent>).  Note these are not FS::agent objects, but hash references of columns and values.
1691
1692 =item agentnum2part_pkg
1693
1694 Hash reference; keys are agentnums, values are array references of available packages for that agent, in the same format as the part_pkg arrayref above.
1695
1696 =item svc_acct_pop
1697
1698 Access numbers - array reference of hash references, each of which has the fields of an svc_acct_pop record (see L<FS::svc_acct_pop>).  Note these are not FS::svc_acct_pop objects, but hash references of columns and values.
1699
1700 =item security_phrase
1701
1702 True if the "security_phrase" feature is enabled
1703
1704 =item payby
1705
1706 Array reference of acceptable payment types for signup
1707
1708 =over 4
1709
1710 =item CARD
1711
1712 credit card - automatic
1713
1714 =item DCRD
1715
1716 credit card - on-demand - version 1.5+ only
1717
1718 =item CHEK
1719
1720 electronic check - automatic
1721
1722 =item DCHK
1723
1724 electronic check - on-demand - version 1.5+ only
1725
1726 =item LECB
1727
1728 Phone bill billing
1729
1730 =item BILL
1731
1732 billing, not recommended for signups
1733
1734 =item COMP
1735
1736 free, definitely not recommended for signups
1737
1738 =item PREPAY
1739
1740 special billing type: applies a credit (see FS::prepay_credit) and sets billing type to BILL
1741
1742 =back
1743
1744 =item cvv_enabled
1745
1746 True if CVV features are available (1.5+ or 1.4.2 with CVV schema patch)
1747
1748 =item msgcat
1749
1750 Hash reference of message catalog values, to support error message customization.  Currently available keys are: passwords_dont_match, invalid_card, unknown_card_type, and not_a (as in "Not a Discover card").  Values are configured in the web interface under "View/Edit message catalog".
1751
1752 =item statedefault
1753
1754 Default state
1755
1756 =item countrydefault
1757
1758 Default country
1759
1760 =back
1761
1762 =item new_customer_minimal HASHREF
1763
1764 Creates a new customer.
1765
1766 Current differences from new_customer: An address is not required.  promo_code
1767 and reg_code are not supported.  If invoicing_list and _password is passed, a
1768 contact will be created with self-service access (no pkgpart or username is
1769 necessary).  No initial billing is run (this may change in a future version).
1770
1771 Takes a hash reference as parameter with the following keys:
1772
1773 =over 4
1774
1775 =item first
1776
1777 first name (required)
1778
1779 =item last
1780
1781 last name (required)
1782
1783 =item ss
1784
1785 (not typically collected; mostly used for ACH transactions)
1786
1787 =item company
1788
1789 Company name
1790
1791 =item address1
1792
1793 Address line one
1794
1795 =item address2
1796
1797 Address line two
1798
1799 =item city
1800
1801 City
1802
1803 =item county
1804
1805 County
1806
1807 =item state
1808
1809 State
1810
1811 =item zip
1812
1813 Zip or postal code
1814
1815 =item daytime
1816
1817 Daytime phone number
1818
1819 =item night
1820
1821 Evening phone number
1822
1823 =item fax
1824
1825 Fax number
1826
1827 =item payby
1828
1829 CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
1830
1831 =item payinfo
1832
1833 Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
1834
1835 =item paycvv
1836
1837 Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
1838
1839 =item paydate
1840
1841 Expiration date for CARD/DCRD
1842
1843 =item payname
1844
1845 Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
1846
1847 =item invoicing_list
1848
1849 comma-separated list of email addresses for email invoices.  The special value 'POST' is used to designate postal invoicing (it may be specified alone or in addition to email addresses),
1850
1851 =item referral_custnum
1852
1853 referring customer number
1854
1855 =item agentnum
1856
1857 Agent number
1858
1859 =item pkgpart
1860
1861 pkgpart of initial package
1862
1863 =item username
1864
1865 Username
1866
1867 =item _password
1868
1869 Password
1870
1871 =item sec_phrase
1872
1873 Security phrase
1874
1875 =item popnum
1876
1877 Access number (index, not the literal number)
1878
1879 =item countrycode
1880
1881 Country code (to be provisioned as a service)
1882
1883 =item phonenum
1884
1885 Phone number (to be provisioned as a service)
1886
1887 =item pin
1888
1889 Voicemail PIN
1890
1891 =back
1892
1893 Returns a hash reference with the following keys:
1894
1895 =over 4
1896
1897 =item error
1898
1899 Empty on success, or an error message on errors.  The special error '_decline' is returned for declined transactions; other error messages should be suitable for display to the user (and are customizable in under Configuration | View/Edit message catalog)
1900
1901 =back
1902
1903 =item new_customer HASHREF
1904
1905 Creates a new customer.  Takes a hash reference as parameter with the
1906 following keys:
1907
1908 =over 4
1909
1910 =item first
1911
1912 first name (required)
1913
1914 =item last
1915
1916 last name (required)
1917
1918 =item ss
1919
1920 (not typically collected; mostly used for ACH transactions)
1921
1922 =item company
1923
1924 Company name
1925
1926 =item address1 (required)
1927
1928 Address line one
1929
1930 =item address2
1931
1932 Address line two
1933
1934 =item city (required)
1935
1936 City
1937
1938 =item county
1939
1940 County
1941
1942 =item state (required)
1943
1944 State
1945
1946 =item zip (required)
1947
1948 Zip or postal code
1949
1950 =item daytime
1951
1952 Daytime phone number
1953
1954 =item night
1955
1956 Evening phone number
1957
1958 =item fax
1959
1960 Fax number
1961
1962 =item payby
1963
1964 CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
1965
1966 =item payinfo
1967
1968 Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
1969
1970 =item paycvv
1971
1972 Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
1973
1974 =item paydate
1975
1976 Expiration date for CARD/DCRD
1977
1978 =item payname
1979
1980 Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
1981
1982 =item invoicing_list
1983
1984 comma-separated list of email addresses for email invoices.  The special value 'POST' is used to designate postal invoicing (it may be specified alone or in addition to email addresses),
1985
1986 =item referral_custnum
1987
1988 referring customer number
1989
1990 =item agentnum
1991
1992 Agent number
1993
1994 =item pkgpart
1995
1996 pkgpart of initial package
1997
1998 =item username
1999
2000 Username
2001
2002 =item _password
2003
2004 Password
2005
2006 =item sec_phrase
2007
2008 Security phrase
2009
2010 =item popnum
2011
2012 Access number (index, not the literal number)
2013
2014 =item countrycode
2015
2016 Country code (to be provisioned as a service)
2017
2018 =item phonenum
2019
2020 Phone number (to be provisioned as a service)
2021
2022 =item pin
2023
2024 Voicemail PIN
2025
2026 =back
2027
2028 Returns a hash reference with the following keys:
2029
2030 =over 4
2031
2032 =item error
2033
2034 Empty on success, or an error message on errors.  The special error '_decline' is returned for declined transactions; other error messages should be suitable for display to the user (and are customizable in under Configuration | View/Edit message catalog)
2035
2036 =back
2037
2038 =item regionselector HASHREF | LIST
2039
2040 Takes as input a hashref or list of key/value pairs with the following keys:
2041
2042 =over 4
2043
2044 =item selected_county
2045
2046 Currently selected county
2047
2048 =item selected_state
2049
2050 Currently selected state
2051
2052 =item selected_country
2053
2054 Currently selected country
2055
2056 =item prefix
2057
2058 Specify a unique prefix string  if you intend to use the HTML output multiple time son one page.
2059
2060 =item onchange
2061
2062 Specify a javascript subroutine to call on changes
2063
2064 =item default_state
2065
2066 Default state
2067
2068 =item default_country
2069
2070 Default country
2071
2072 =item locales
2073
2074 An arrayref of hash references specifying regions.  Normally you can just pass the value of the I<cust_main_county> field returned by B<signup_info>.
2075
2076 =back
2077
2078 Returns a list consisting of three HTML fragments for county selection,
2079 state selection and country selection, respectively.
2080
2081 =cut
2082
2083 #false laziness w/FS::cust_main_county (this is currently the "newest" version)
2084 sub regionselector {
2085   my $param;
2086   if ( ref($_[0]) ) {
2087     $param = shift;
2088   } else {
2089     $param = { @_ };
2090   }
2091   $param->{'selected_country'} ||= $param->{'default_country'};
2092   $param->{'selected_state'} ||= $param->{'default_state'};
2093
2094   my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : '';
2095
2096   my $countyflag = 0;
2097
2098   my %cust_main_county;
2099
2100 #  unless ( @cust_main_county ) { #cache 
2101     #@cust_main_county = qsearch('cust_main_county', {} );
2102     #foreach my $c ( @cust_main_county ) {
2103     foreach my $c ( @{ $param->{'locales'} } ) {
2104       #$countyflag=1 if $c->county;
2105       $countyflag=1 if $c->{county};
2106       #push @{$cust_main_county{$c->country}{$c->state}}, $c->county;
2107       #$cust_main_county{$c->country}{$c->state}{$c->county} = 1;
2108       $cust_main_county{$c->{country}}{$c->{state}}{$c->{county}} = 1;
2109     }
2110 #  }
2111   $countyflag=1 if $param->{selected_county};
2112
2113   my $script_html = <<END;
2114     <SCRIPT>
2115     function opt(what,value,text) {
2116       var optionName = new Option(text, value, false, false);
2117       var length = what.length;
2118       what.options[length] = optionName;
2119     }
2120     function ${prefix}country_changed(what) {
2121       country = what.options[what.selectedIndex].text;
2122       for ( var i = what.form.${prefix}state.length; i >= 0; i-- )
2123           what.form.${prefix}state.options[i] = null;
2124 END
2125       #what.form.${prefix}state.options[0] = new Option('', '', false, true);
2126
2127   foreach my $country ( sort keys %cust_main_county ) {
2128     $script_html .= "\nif ( country == \"$country\" ) {\n";
2129     foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
2130       my $text = $state || '(n/a)';
2131       $script_html .= qq!opt(what.form.${prefix}state, "$state", "$text");\n!;
2132     }
2133     $script_html .= "}\n";
2134   }
2135
2136   $script_html .= <<END;
2137     }
2138     function ${prefix}state_changed(what) {
2139 END
2140
2141   if ( $countyflag ) {
2142     $script_html .= <<END;
2143       state = what.options[what.selectedIndex].text;
2144       country = what.form.${prefix}country.options[what.form.${prefix}country.selectedIndex].text;
2145       for ( var i = what.form.${prefix}county.length; i >= 0; i-- )
2146           what.form.${prefix}county.options[i] = null;
2147 END
2148
2149     foreach my $country ( sort keys %cust_main_county ) {
2150       $script_html .= "\nif ( country == \"$country\" ) {\n";
2151       foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
2152         $script_html .= "\nif ( state == \"$state\" ) {\n";
2153           #foreach my $county ( sort @{$cust_main_county{$country}{$state}} ) {
2154           foreach my $county ( sort keys %{$cust_main_county{$country}{$state}} ) {
2155             my $text = $county || '(n/a)';
2156             $script_html .=
2157               qq!opt(what.form.${prefix}county, "$county", "$text");\n!;
2158           }
2159         $script_html .= "}\n";
2160       }
2161       $script_html .= "}\n";
2162     }
2163   }
2164
2165   $script_html .= <<END;
2166     }
2167     </SCRIPT>
2168 END
2169
2170   my $county_html = $script_html;
2171   if ( $countyflag ) {
2172     $county_html .= qq!<SELECT NAME="${prefix}county" onChange="$param->{'onchange'}">!;
2173     foreach my $county ( 
2174       sort keys %{ $cust_main_county{$param->{'selected_country'}}{$param->{'selected_state'}} }
2175     ) {
2176       my $text = $county || '(n/a)';
2177       $county_html .= qq!<OPTION VALUE="$county"!.
2178                       ($county eq $param->{'selected_county'} ? 
2179                         ' SELECTED>' : 
2180                         '>'
2181                       ).
2182                       $text.
2183                       '</OPTION>';
2184     }
2185     $county_html .= '</SELECT>';
2186   } else {
2187     $county_html .=
2188       qq!<INPUT TYPE="hidden" NAME="${prefix}county" VALUE="$param->{'selected_county'}">!;
2189   }
2190
2191   my $state_html = qq!<SELECT NAME="${prefix}state" !.
2192                    qq!onChange="${prefix}state_changed(this); $param->{'onchange'}">!;
2193   foreach my $state ( sort keys %{ $cust_main_county{$param->{'selected_country'}} } ) {
2194     my $text = $state || '(n/a)';
2195     my $selected = $state eq $param->{'selected_state'} ? 'SELECTED' : '';
2196     $state_html .= "\n<OPTION $selected VALUE=$state>$text</OPTION>"
2197   }
2198   $state_html .= '</SELECT>';
2199
2200   my $country_html = '';
2201   if ( scalar( keys %cust_main_county ) > 1 )  {
2202
2203     $country_html = qq(<SELECT NAME="${prefix}country" ).
2204                     qq(onChange="${prefix}country_changed(this); ).
2205                                  $param->{'onchange'}.
2206                                '"'.
2207                       '>';
2208     my $countrydefault = $param->{default_country} || 'US';
2209     foreach my $country (
2210       sort { ($b eq $countrydefault) <=> ($a eq $countrydefault) or $a cmp $b }
2211         keys %cust_main_county
2212     ) {
2213       my $selected = $country eq $param->{'selected_country'}
2214                        ? ' SELECTED'
2215                        : '';
2216       $country_html .= "\n<OPTION$selected>$country</OPTION>"
2217     }
2218     $country_html .= '</SELECT>';
2219   } else {
2220
2221     $country_html = qq(<INPUT TYPE="hidden" NAME="${prefix}country" ).
2222                             ' VALUE="'. (keys %cust_main_county )[0]. '">';
2223
2224   }
2225
2226   ($county_html, $state_html, $country_html);
2227
2228 }
2229
2230 sub regionselector_hashref {
2231   my ($county_html, $state_html, $country_html) = regionselector(@_);
2232   {
2233     'county_html'  => $county_html,
2234     'state_html'   => $state_html,
2235     'country_html' => $country_html,
2236   };
2237 }
2238
2239 =item location_form HASHREF | LIST
2240
2241 Takes as input a hashref or list of key/value pairs with the following keys:
2242
2243 =over 4
2244
2245 =item session_id
2246
2247 Current customer session_id
2248
2249 =item no_asterisks
2250
2251 Omit red asterisks from required fields.
2252
2253 =item address1_label
2254
2255 Label for first address line.
2256
2257 =back
2258
2259 Returns an HTML fragment for a location form (address, city, state, zip,
2260 country)
2261
2262 =cut
2263
2264 sub location_form {
2265   my $param;
2266   if ( ref($_[0]) ) {
2267     $param = shift;
2268   } else {
2269     $param = { @_ };
2270   }
2271
2272   my $session_id = delete $param->{'session_id'};
2273
2274   my $rv = mason_comp( 'session_id' => $session_id,
2275                        'comp'       => '/elements/location.html',
2276                        'args'       => [ %$param ],
2277                      );
2278
2279   #hmm.
2280   $rv->{'error'} || $rv->{'output'};
2281
2282 }
2283
2284
2285 #=item expselect HASHREF | LIST
2286 #
2287 #Takes as input a hashref or list of key/value pairs with the following keys:
2288 #
2289 #=over 4
2290 #
2291 #=item prefix - Specify a unique prefix string  if you intend to use the HTML output multiple time son one page.
2292 #
2293 #=item date - current date, in yyyy-mm-dd or m-d-yyyy format
2294 #
2295 #=back
2296
2297 =item expselect PREFIX [ DATE ]
2298
2299 Takes as input a unique prefix string and the current expiration date, in
2300 yyyy-mm-dd or m-d-yyyy format
2301
2302 Returns an HTML fragments for expiration date selection.
2303
2304 =cut
2305
2306 sub expselect {
2307   #my $param;
2308   #if ( ref($_[0]) ) {
2309   #  $param = shift;
2310   #} else {
2311   #  $param = { @_ };
2312   #my $prefix = $param->{'prefix'};
2313   #my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : '';
2314   #my $date =   exists($param->{'date'})   ? $param->{'date'}   : '';
2315   my $prefix = shift;
2316   my $date = scalar(@_) ? shift : '';
2317
2318   my( $m, $y ) = ( 0, 0 );
2319   if ( $date  =~ /^(\d{4})-(\d{2})-\d{2}$/ ) { #PostgreSQL date format
2320     ( $m, $y ) = ( $2, $1 );
2321   } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) {
2322     ( $m, $y ) = ( $1, $3 );
2323   }
2324   my $return = qq!<SELECT NAME="$prefix!. qq!_month" SIZE="1">!;
2325   for ( 1 .. 12 ) {
2326     $return .= qq!<OPTION VALUE="$_"!;
2327     $return .= " SELECTED" if $_ == $m;
2328     $return .= ">$_";
2329   }
2330   $return .= qq!</SELECT>/<SELECT NAME="$prefix!. qq!_year" SIZE="1">!;
2331   my @t = localtime;
2332   my $thisYear = $t[5] + 1900;
2333   for ( ($thisYear > $y && $y > 0 ? $y : $thisYear) .. ($thisYear+10) ) {
2334     $return .= qq!<OPTION VALUE="$_"!;
2335     $return .= " SELECTED" if $_ == $y;
2336     $return .= ">$_";
2337   }
2338   $return .= "</SELECT>";
2339
2340   $return;
2341 }
2342
2343 =item popselector HASHREF | LIST
2344
2345 Takes as input a hashref or list of key/value pairs with the following keys:
2346
2347 =over 4
2348
2349 =item popnum
2350
2351 Access number number
2352
2353 =item pops
2354
2355 An arrayref of hash references specifying access numbers.  Normally you can just pass the value of the I<svc_acct_pop> field returned by B<signup_info>.
2356
2357 =back
2358
2359 Returns an HTML fragment for access number selection.
2360
2361 =cut
2362
2363 #horrible false laziness with FS/FS/svc_acct_pop.pm::popselector
2364 sub popselector {
2365   my $param;
2366   if ( ref($_[0]) ) {
2367     $param = shift;
2368   } else {
2369     $param = { @_ };
2370   }
2371   my $popnum = $param->{'popnum'};
2372   my $pops = $param->{'pops'};
2373
2374   return '<INPUT TYPE="hidden" NAME="popnum" VALUE="">' unless @$pops;
2375   return $pops->[0]{city}. ', '. $pops->[0]{state}.
2376          ' ('. $pops->[0]{ac}. ')/'. $pops->[0]{exch}. '-'. $pops->[0]{loc}.
2377          '<INPUT TYPE="hidden" NAME="popnum" VALUE="'. $pops->[0]{popnum}. '">'
2378     if scalar(@$pops) == 1;
2379
2380   my %pop = ();
2381   my %popnum2pop = ();
2382   foreach (@$pops) {
2383     push @{ $pop{ $_->{state} }->{ $_->{ac} } }, $_;
2384     $popnum2pop{$_->{popnum}} = $_;
2385   }
2386
2387   my $text = <<END;
2388     <SCRIPT>
2389     function opt(what,href,text) {
2390       var optionName = new Option(text, href, false, false)
2391       var length = what.length;
2392       what.options[length] = optionName;
2393     }
2394 END
2395
2396   my $init_popstate = $param->{'init_popstate'};
2397   if ( $init_popstate ) {
2398     $text .= '<INPUT TYPE="hidden" NAME="init_popstate" VALUE="'.
2399              $init_popstate. '">';
2400   } else {
2401     $text .= <<END;
2402       function acstate_changed(what) {
2403         state = what.options[what.selectedIndex].text;
2404         what.form.popac.options.length = 0
2405         what.form.popac.options[0] = new Option("Area code", "-1", false, true);
2406 END
2407   } 
2408
2409   my @states = $init_popstate ? ( $init_popstate ) : keys %pop;
2410   foreach my $state ( sort { $a cmp $b } @states ) {
2411     $text .= "\nif ( state == \"$state\" ) {\n" unless $init_popstate;
2412
2413     foreach my $ac ( sort { $a cmp $b } keys %{ $pop{$state} }) {
2414       $text .= "opt(what.form.popac, \"$ac\", \"$ac\");\n";
2415       if ($ac eq $param->{'popac'}) {
2416         $text .= "what.form.popac.options[what.form.popac.length-1].selected = true;\n";
2417       }
2418     }
2419     $text .= "}\n" unless $init_popstate;
2420   }
2421   $text .= "popac_changed(what.form.popac)}\n";
2422
2423   $text .= <<END;
2424   function popac_changed(what) {
2425     ac = what.options[what.selectedIndex].text;
2426     what.form.popnum.options.length = 0;
2427     what.form.popnum.options[0] = new Option("City", "-1", false, true);
2428
2429 END
2430
2431   foreach my $state ( @states ) {
2432     foreach my $popac ( keys %{ $pop{$state} } ) {
2433       $text .= "\nif ( ac == \"$popac\" ) {\n";
2434
2435       foreach my $pop ( @{$pop{$state}->{$popac}}) {
2436         my $o_popnum = $pop->{popnum};
2437         my $poptext =  $pop->{city}. ', '. $pop->{state}.
2438                        ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc};
2439
2440         $text .= "opt(what.form.popnum, \"$o_popnum\", \"$poptext\");\n";
2441         if ($popnum == $o_popnum) {
2442           $text .= "what.form.popnum.options[what.form.popnum.length-1].selected = true;\n";
2443         }
2444       }
2445       $text .= "}\n";
2446     }
2447   }
2448
2449
2450   $text .= "}\n</SCRIPT>\n";
2451
2452   $param->{'acstate'} = '' unless defined($param->{'acstate'});
2453
2454   $text .=
2455     qq!<TABLE CELLPADDING="0"><TR><TD><SELECT NAME="acstate"! .
2456     qq!SIZE=1 onChange="acstate_changed(this)"><OPTION VALUE=-1>State!;
2457   $text .= "<OPTION" . ($_ eq $param->{'acstate'} ? " SELECTED" : "") .
2458            ">$_" foreach sort { $a cmp $b } @states;
2459   $text .= '</SELECT>'; #callback? return 3 html pieces?  #'</TD>';
2460
2461   $text .=
2462     qq!<SELECT NAME="popac" SIZE=1 onChange="popac_changed(this)">!.
2463     qq!<OPTION>Area code</SELECT></TR><TR VALIGN="top">!;
2464
2465   $text .= qq!<TR><TD><SELECT NAME="popnum" SIZE=1 STYLE="width: 20em"><OPTION>City!;
2466
2467
2468   #comment this block to disable initial list polulation
2469   my @initial_select = ();
2470   if ( scalar( @$pops ) > 100 ) {
2471     push @initial_select, $popnum2pop{$popnum} if $popnum2pop{$popnum};
2472   } else {
2473     @initial_select = @$pops;
2474   }
2475   foreach my $pop ( sort { $a->{state} cmp $b->{state} } @initial_select ) {
2476     $text .= qq!<OPTION VALUE="!. $pop->{popnum}. '"'.
2477              ( ( $popnum && $pop->{popnum} == $popnum ) ? ' SELECTED' : '' ). ">".
2478              $pop->{city}. ', '. $pop->{state}.
2479                ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc};
2480   }
2481
2482   $text .= qq!</SELECT></TD></TR></TABLE>!;
2483
2484   $text;
2485
2486 }
2487
2488 =item domainselector HASHREF | LIST
2489
2490 Takes as input a hashref or list of key/value pairs with the following keys:
2491
2492 =over 4
2493
2494 =item pkgnum
2495
2496 Package number
2497
2498 =item domsvc
2499
2500 Service number of the selected item.
2501
2502 =back
2503
2504 Returns an HTML fragment for domain selection.
2505
2506 =cut
2507
2508 sub domainselector {
2509   my $param;
2510   if ( ref($_[0]) ) {
2511     $param = shift;
2512   } else {
2513     $param = { @_ };
2514   }
2515   my $domsvc= $param->{'domsvc'};
2516   my $rv = 
2517       domain_select_hash(map {$_ => $param->{$_}} qw(pkgnum svcpart pkgpart) );
2518   my $domains = $rv->{'domains'};
2519   $domsvc = $rv->{'domsvc'} unless $domsvc;
2520
2521   return '<INPUT TYPE="hidden" NAME="domsvc" VALUE="">'
2522     unless scalar(keys %$domains);
2523
2524   if (scalar(keys %$domains) == 1) {
2525     my $key;
2526     foreach(keys %$domains) {
2527       $key = $_;
2528     }
2529     return '<TR><TD ALIGN="right">Domain</TD><TD>'. $domains->{$key}.
2530            '<INPUT TYPE="hidden" NAME="domsvc" VALUE="'. $key. '"></TD></TR>'
2531   }
2532
2533   my $text .= qq!<TR><TD ALIGN="right">Domain</TD><TD><SELECT NAME="domsvc" SIZE=1 STYLE="width: 20em">!;
2534
2535   $text .= '<OPTION>(Choose Domain)' unless $domsvc;
2536
2537   foreach my $domain ( sort { $domains->{$a} cmp $domains->{$b} } keys %$domains ) {
2538     $text .= qq!<OPTION VALUE="!. $domain. '"'.
2539              ( ( $domsvc && $domain == $domsvc ) ? ' SELECTED' : '' ). ">".
2540              $domains->{$domain};
2541   }
2542
2543   $text .= qq!</SELECT></TD></TR>!;
2544
2545   $text;
2546
2547 }
2548
2549 =item didselector HASHREF | LIST
2550
2551 Takes as input a hashref or list of key/value pairs with the following keys:
2552
2553 =over 4
2554
2555 =item field
2556
2557 Field name for the returned HTML fragment.
2558
2559 =item svcpart
2560
2561 Service definition (see L<FS::part_svc>)
2562
2563 =back
2564
2565 Returns an HTML fragment for DID selection.
2566
2567 =cut
2568
2569 sub didselector {
2570   my $param;
2571   if ( ref($_[0]) ) {
2572     $param = shift;
2573   } else {
2574     $param = { @_ };
2575   }
2576
2577   my $rv = mason_comp( 'comp'=>'/elements/select-did.html',
2578                        'args'=>[ %$param ],
2579                      );
2580
2581   #hmm.
2582   $rv->{'error'} || $rv->{'output'};
2583
2584 }
2585
2586 =back
2587
2588 =head1 RESELLER FUNCTIONS
2589
2590 Note: Resellers can also use the B<signup_info> and B<new_customer> functions
2591 with their active session, and the B<customer_info> and B<order_pkg> functions
2592 with their active session and an additional I<custnum> parameter.
2593
2594 For the most part, development of the reseller web interface has been
2595 superceded by agent-virtualized access to the backend.
2596
2597 =over 4
2598
2599 =item agent_login
2600
2601 Agent login
2602
2603 =item agent_info
2604
2605 Agent info
2606
2607 =item agent_list_customers
2608
2609 List agent's customers.
2610
2611 =back
2612
2613 =head1 BUGS
2614
2615 =head1 SEE ALSO
2616
2617 L<freeside-selfservice-clientd>, L<freeside-selfservice-server>
2618
2619 =cut
2620
2621 1;
2622