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