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