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