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