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