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