Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / fs_selfservice / FS-SelfService / SelfService.pm
index ec4668f..765d611 100644 (file)
@@ -1,7 +1,8 @@
 package FS::SelfService;
 
 use strict;
-use vars qw($VERSION @ISA @EXPORT_OK $DEBUG $dir $socket %autoload $tag);
+use vars qw( $VERSION @ISA @EXPORT_OK $DEBUG
+             $skip_uid_check $dir $socket %autoload $tag );
 use Exporter;
 use Socket;
 use FileHandle;
@@ -24,41 +25,110 @@ $socket .= '.'.$tag if defined $tag && length($tag);
   'passwd'                    => 'passwd/passwd',
   'chfn'                      => 'passwd/passwd',
   'chsh'                      => 'passwd/passwd',
+  'login_info'                => 'MyAccount/login_info',
+  'login_banner_image'        => 'MyAccount/login_banner_image',
   'login'                     => 'MyAccount/login',
   'logout'                    => 'MyAccount/logout',
+  'switch_acct'               => 'MyAccount/switch_acct',
+  'switch_cust'               => 'MyAccount/switch_cust',
   'customer_info'             => 'MyAccount/customer_info',
+  'customer_info_short'       => 'MyAccount/customer_info_short',
+  'billing_history'           => 'MyAccount/billing_history',
   'edit_info'                 => 'MyAccount/edit_info',     #add to ss cgi!
   'invoice'                   => 'MyAccount/invoice',
+  'invoice_pdf'               => 'MyAccount/invoice_pdf',
+  'legacy_invoice'            => 'MyAccount/legacy_invoice',
+  'legacy_invoice_pdf'        => 'MyAccount/legacy_invoice_pdf',
   'invoice_logo'              => 'MyAccount/invoice_logo',
   'list_invoices'             => 'MyAccount/list_invoices', #?
   'cancel'                    => 'MyAccount/cancel',        #add to ss cgi!
   'payment_info'              => 'MyAccount/payment_info',
+  'payment_info_renew_info'   => 'MyAccount/payment_info_renew_info',
   'process_payment'           => 'MyAccount/process_payment',
+  'store_payment'             => 'MyAccount/store_payment',
+  'process_stored_payment'    => 'MyAccount/process_stored_payment',
   'process_payment_order_pkg' => 'MyAccount/process_payment_order_pkg',
+  'process_payment_change_pkg' => 'MyAccount/process_payment_change_pkg',
+  'process_payment_order_renew' => 'MyAccount/process_payment_order_renew',
   'process_prepay'            => 'MyAccount/process_prepay',
+  'realtime_collect'          => 'MyAccount/realtime_collect',
   'list_pkgs'                 => 'MyAccount/list_pkgs',     #add to ss (added?)
   'list_svcs'                 => 'MyAccount/list_svcs',     #add to ss (added?)
   'list_svc_usage'            => 'MyAccount/list_svc_usage',   
+  'svc_status_html'           => 'MyAccount/svc_status_html',
+  'svc_status_hash'           => 'MyAccount/svc_status_hash',
+  'set_svc_status_hash'       => 'MyAccount/set_svc_status_hash',
+  'set_svc_status_listadd'    => 'MyAccount/set_svc_status_listadd',
+  'set_svc_status_listdel'    => 'MyAccount/set_svc_status_listdel',
+  'set_svc_status_vacationadd'=> 'MyAccount/set_svc_status_vacationadd',
+  'set_svc_status_vacationdel'=> 'MyAccount/set_svc_status_vacationdel',
+  'acct_forward_info'         => 'MyAccount/acct_forward_info',
+  'process_acct_forward'      => 'MyAccount/process_acct_forward',
+  'list_dsl_devices'          => 'MyAccount/list_dsl_devices',   
+  'add_dsl_device'            => 'MyAccount/add_dsl_device',   
+  'delete_dsl_device'         => 'MyAccount/delete_dsl_device',   
+  'port_graph'                => 'MyAccount/port_graph',   
+  'list_cdr_usage'            => 'MyAccount/list_cdr_usage',   
   'list_support_usage'        => 'MyAccount/list_support_usage',   
   'order_pkg'                 => 'MyAccount/order_pkg',     #add to ss cgi!
   'change_pkg'                => 'MyAccount/change_pkg', 
   'order_recharge'            => 'MyAccount/order_recharge',
+  'renew_info'                => 'MyAccount/renew_info',
+  'order_renew'               => 'MyAccount/order_renew',
   'cancel_pkg'                => 'MyAccount/cancel_pkg',    #add to ss cgi!
+  'suspend_pkg'               => 'MyAccount/suspend_pkg',   #add to ss cgi!
   'charge'                    => 'MyAccount/charge',        #?
   'part_svc_info'             => 'MyAccount/part_svc_info',
   'provision_acct'            => 'MyAccount/provision_acct',
+  'provision_phone'           => 'MyAccount/provision_phone',
   'provision_external'        => 'MyAccount/provision_external',
   'unprovision_svc'           => 'MyAccount/unprovision_svc',
   'myaccount_passwd'          => 'MyAccount/myaccount_passwd',
+  'reset_passwd'              => 'MyAccount/reset_passwd',
+  'check_reset_passwd'        => 'MyAccount/check_reset_passwd',
+  'process_reset_passwd'      => 'MyAccount/process_reset_passwd',
+  'list_tickets'              => 'MyAccount/list_tickets',
+  'create_ticket'             => 'MyAccount/create_ticket',
+  'get_ticket'                => 'MyAccount/get_ticket',
+  'adjust_ticket_priority'    => 'MyAccount/adjust_ticket_priority',
+  'did_report'                => 'MyAccount/did_report',
   'signup_info'               => 'Signup/signup_info',
+  'skin_info'                 => 'MyAccount/skin_info',
+  'access_info'               => 'MyAccount/access_info',
   'domain_select_hash'        => 'Signup/domain_select_hash',  # expose?
   'new_customer'              => 'Signup/new_customer',
+  'new_customer_minimal'      => 'Signup/new_customer_minimal',
+  'capture_payment'           => 'Signup/capture_payment',
+  #N/A 'clear_signup_cache'        => 'Signup/clear_cache',
+  'new_agent'                 => 'Agent/new_agent',
   'agent_login'               => 'Agent/agent_login',
   'agent_logout'              => 'Agent/agent_logout',
   'agent_info'                => 'Agent/agent_info',
   'agent_list_customers'      => 'Agent/agent_list_customers',
+  'check_username'            => 'Agent/check_username',
+  'suspend_username'          => 'Agent/suspend_username',
+  'unsuspend_username'        => 'Agent/unsuspend_username',
+  'mason_comp'                => 'MasonComponent/mason_comp',
+  'call_time'                 => 'PrepaidPhone/call_time',
+  'call_time_nanpa'           => 'PrepaidPhone/call_time_nanpa',
+  'phonenum_balance'          => 'PrepaidPhone/phonenum_balance',
+
+  'start_thirdparty'          => 'MyAccount/start_thirdparty',
+  'finish_thirdparty'         => 'MyAccount/finish_thirdparty',
+
+  'quotation_info'            => 'MyAccount/quotation/quotation_info',
+  'quotation_print'           => 'MyAccount/quotation/quotation_print',
+  'quotation_add_pkg'         => 'MyAccount/quotation/quotation_add_pkg',
+  'quotation_remove_pkg'      => 'MyAccount/quotation/quotation_remove_pkg',
+  'quotation_order'           => 'MyAccount/quotation/quotation_order',
+
+);
+@EXPORT_OK = (
+  keys(%autoload),
+  qw( regionselector regionselector_hashref location_form
+      expselect popselector domainselector didselector
+    )
 );
-@EXPORT_OK = ( keys(%autoload), qw( regionselector expselect popselector domainselector) );
 
 $ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin';
 $ENV{'SHELL'} = '/bin/sh';
@@ -67,8 +137,11 @@ $ENV{'CDPATH'} = '';
 $ENV{'ENV'} = '';
 $ENV{'BASH_ENV'} = '';
 
+#you can add BEGIN { $FS::SelfService::skip_uid_check = 1; } 
+#if you grant appropriate permissions to whatever user
 my $freeside_uid = scalar(getpwnam('freeside'));
-die "not running as the freeside user\n" if $> != $freeside_uid;
+die "not running as the freeside user\n"
+  if $> != $freeside_uid && ! $skip_uid_check;
 
 -e $dir or die "FATAL: $dir doesn't exist!";
 -d $dir or die "FATAL: $dir isn't a directory!";
@@ -137,17 +210,43 @@ FS::SelfService - Freeside self-service API
   # "my account" functionality
   use FS::SelfService qw( login customer_info invoice cancel payment_info process_payment );
 
+  #new-style login with an email address and password
+  # can also be used for svc_acct login, set $emailaddress to username@domain
+  my $rv = login ( { 'email'    => $emailaddress,
+                     'password' => $password,
+                   },
+                 );
+  if ( $rv->{'error'} ) {
+    #handle login error...
+  } else {
+    #successful login
+    $session_id = $rv->{'session_id'};
+  }
+
+  #classic svc_acct-based login with separate username and password
   my $rv = login( { 'username' => $username,
                     'domain'   => $domain,
                     'password' => $password,
                   }
                 );
+  if ( $rv->{'error'} ) {
+    #handle login error...
+  } else {
+    #successful login
+    $session_id = $rv->{'session_id'};
+  }
 
+  #svc_phone login with phone number and PIN
+  my $rv = login( { 'username' => $phone_number,
+                    'domain'   => 'svc_phone',
+                    'password' => $pin,
+                  }
+                );
   if ( $rv->{'error'} ) {
     #handle login error...
   } else {
     #successful login
-    my $session_id = $rv->{'session_id'};
+    $session_id = $rv->{'session_id'};
   }
 
   my $customer_info = customer_info( { 'session_id' => $session_id } );
@@ -159,12 +258,35 @@ FS::SelfService - Freeside self-service API
 
   #!!! list_pkgs example
 
-  #!!! order_pkg example
+  #ordering a package with an svc_acct service
+  my $rv = order_pkg( { 'session_id' => $session_id,
+                        'pkgpart'    => $pkgpart,
+                        'svcpart'    => $svcpart,
+                        'username'   => $username,
+                        'domsvc'     => $domsvc, #svcnum of svc_domain
+                        '_password'  => $password,
+                      }
+                    );
+
+  #!!! ordering a package with an svc_domain service example
+
+  #!!! ordering a package with an svc_phone service example
+
+  #!!! ordering a package with an svc_external service example
+
+  #!!! ordering a package with an svc_pbx service
+
+  #ordering a package with no service
+  my $rv = order_pkg( { 'session_id' => $session_id,
+                        'pkgpart'    => $pkgpart,
+                        'svcpart'    => 'none',
+                      }
+                    );
 
   #!!! cancel_pkg example
 
   # signup functionality
-  use FS::SelfService qw( signup_info new_customer );
+  use FS::SelfService qw( signup_info new_customer new_customer_minimal );
 
   my $signup_info = signup_info;
 
@@ -192,11 +314,16 @@ FS::SelfService - Freeside self-service API
                         'payname'          => $payname,
                         'invoicing_list'   => $invoicing_list,
                         'referral_custnum' => $referral_custnum,
+                        'agentnum'         => $agentnum,
                         'pkgpart'          => $pkgpart,
+
                         'username'         => $username,
                         '_password'        => $password,
                         'popnum'           => $popnum,
-                        'agentnum'         => $agentnum,
+                        #OR
+                        'countrycode'      => 1,
+                        'phonenum'         => $phonenum,
+                        'pin'              => $pin,
                       }
                     );
   
@@ -222,6 +349,37 @@ see XXXX instead.
 
 =item passwd
 
+Changes the password for an existing user in svc_acct.  Takes a hash
+reference with the following keys:
+
+=over 4
+
+=item username
+
+Username of the account (required)
+
+=item domain
+
+Domain of the account (required)
+
+=item old_password
+
+Old password (required)
+
+=item new_password
+New password (required)
+
+=item new_gecos
+
+New gecos
+
+=item new_shell
+
+New Shell
+
+=back 
+
 =item chfn
 
 =item chsh
@@ -239,6 +397,11 @@ following keys:
 
 =over 4
 
+=item email
+
+Email address (username@domain), instead of username and domain.  Required for
+contact-based self-service login, can also be used for svc_acct-based login.
+
 =item username
 
 Username
@@ -451,10 +614,14 @@ Array reference of all states in the current default country.
 Hash reference of card types; keys are card types, values are the exact strings
 passed to the process_payment function
 
-=item paybatch
+=cut
 
-Unique transaction identifier (prevents multiple charges), passed to the
-process_payment function
+#this doesn't actually work yet
+#
+#=item paybatch
+#
+#Unique transaction identifier (prevents multiple charges), passed to the
+#process_payment function
 
 =back
 
@@ -508,6 +675,10 @@ State
 
 Zip or postal code
 
+=item country
+
+Two-letter country code
+
 =item payinfo
 
 Card number
@@ -520,15 +691,47 @@ Card expiration month
 
 Card expiration year
 
-=item paybatch
+=cut
 
-Unique transaction identifier, returned from the payment_info function.
-Prevents multiple charges.
+#this doesn't actually work yet
+#
+#=item paybatch
+#
+#Unique transaction identifier, returned from the payment_info function.
+#Prevents multiple charges.
 
 =back
 
 Returns a hash reference with a single key, B<error>, empty on success, or an
-error message on errors
+error message on errors.
+
+=item process_payment_order_pkg
+
+Combines the B<process_payment> and B<order_pkg> functions in one step.  If the
+payment processes sucessfully, the package is ordered.  Takes a hash reference
+as parameter with the keys of both methods.
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=item process_payment_change_pkg
+
+Combines the B<process_payment> and B<change_pkg> functions in one step.  If the
+payment processes sucessfully, the package is ordered.  Takes a hash reference
+as parameter with the keys of both methods.
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+
+=item process_payment_order_renew
+
+Combines the B<process_payment> and B<order_renew> functions in one step.  If
+the payment processes sucessfully, the renewal is processed.  Takes a hash
+reference as parameter with the keys of both methods.
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
 
 =item list_pkgs
 
@@ -545,6 +748,10 @@ Returns a hash reference containing customer package information.  The hash refe
 
 Customer number
 
+=item error
+
+Empty on success, or an error message on errors.
+
 =item cust_pkg HASHREF
 
 Array reference of hash references, each of which has the fields of a cust_pkg
@@ -591,15 +798,7 @@ already provisioned for this specific cust_pkg.  Each has the following keys:
 
 =item label
 
-Array reference with three elements:
-
-=over 4
-
-=item Name of this service
-
-=item Meaningful user-specific identifier for the service (i.e. username, domain or mail alias)
-
-=item Table name of this service
+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.
 
 =back
 
@@ -609,11 +808,11 @@ Primary key for this service
 
 =item svcpart
 
-Service definition (part_pkg)
+Service definition (see L<FS::part_svc>)
 
 =item pkgnum
 
-Customer package (cust_pkg)
+Customer package (see L<FS::cust_pkg>)
 
 =item overlimit
 
@@ -623,12 +822,6 @@ Blank if the service is not over limit, or the date the service exceeded its usa
 
 =back
 
-=item error
-
-Empty on success, or an error message on errors.
-
-=back
-
 =item list_svcs
 
 Returns service information for this customer.
@@ -667,6 +860,8 @@ mail alias).
 
 Account (svc_acct) services also have the following keys:
 
+=over 4
+
 =item username
 
 Username
@@ -729,13 +924,41 @@ Session identifier
 
 =item pkgpart
 
-pkgpart of package to order
+Package to order (see L<FS::part_pkg>).
+
+=item quantity
+
+Quantity for this package order (default 1).
+
+=item locationnum
+
+Optional locationnum for this package order, for existing locations.
+
+Or, for new locations, pass the following fields: address1*, address2, city*,
+county, state*, zip*, country.  (* = required in this case)
+
+=item address1
+
+=item address 2
+
+=item city
+
+=item 
 
 =item svcpart
 
-optional svcpart, required only if the package definition does not contain
-one svc_acct service definition with quantity 1 (it may contain others with
-quantity >1)
+Service to order (see L<FS::part_svc>).
+
+Normally optional; required only to provision a non-svc_acct service, or if the
+package definition does not contain one svc_acct service definition with
+quantity 1 (it may contain others with quantity >1).  A svcpart of "none" can
+also be specified to indicate that no initial service should be provisioned.
+
+=back
+
+Fields used when provisioning an svc_acct service:
+
+=over 4
 
 =item username
 
@@ -755,214 +978,498 @@ Optional Access number number
 
 =back
 
-Returns a hash reference with a single key, B<error>, empty on success, or an
-error message on errors.  The special error '_decline' is returned for
-declined transactions.
+Fields used when provisioning an svc_domain service:
 
-=item cancel_pkg
+=over 4
 
-Cancels a package for this customer.
+=item domain
 
-Takes a hash reference as parameter with the following keys:
+Domain
+
+=back
+
+Fields used when provisioning an svc_phone service:
 
 =over 4
 
-=item session_id
+=item phonenum
 
-Session identifier
+Phone number
 
-=item pkgpart
+=item pin
 
-pkgpart of package to cancel
+Voicemail PIN
 
-=back
+=item sip_password
 
-Returns a hash reference with a single key, B<error>, empty on success, or an
-error message on errors.
+SIP password
 
 =back
 
-=head1 SIGNUP FUNCTIONS
+Fields used when provisioning an svc_external service:
 
 =over 4
 
-=item signup_info HASHREF
+=item id
 
-Takes a hash reference as parameter with the following keys:
+External numeric ID.
 
-=over 4
+=item title
 
-=item session_id - Optional agent/reseller interface session
+External text title.
 
 =back
 
-Returns a hash reference containing information that may be useful in
-displaying a signup page.  The hash reference contains the following keys:
+Fields used when provisioning an svc_pbx service:
 
 =over 4
 
-=item cust_main_county
-
-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.
-
-=item part_pkg
-
-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
-an agentnum specified explicitly via reseller interface session_id in the
-options.
-
-=item agent
-
-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.
+=item id
 
-=item agentnum2part_pkg
+Numeric ID.
 
-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.
+=item name
 
-=item svc_acct_pop
+Text name.
 
-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.
+=back
 
-=item security_phrase
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.  The special error '_decline' is returned for
+declined transactions.
 
-True if the "security_phrase" feature is enabled
+=item change_pkg
 
-=item payby
+Changes a package for this customer.
 
-Array reference of acceptable payment types for signup
+Takes a hash reference as parameter with the following keys:
 
 =over 4
 
-=item CARD
-
-credit card - automatic
+=item session_id
 
-=item DCRD
+Session identifier
 
-credit card - on-demand - version 1.5+ only
+=item pkgnum
 
-=item CHEK
+Existing customer package.
 
-electronic check - automatic
+=item pkgpart
 
-=item DCHK
+New package to order (see L<FS::part_pkg>).
 
-electronic check - on-demand - version 1.5+ only
+=item quantity
 
-=item LECB
+Quantity for this package order (default 1).
 
-Phone bill billing
+=back
 
-=item BILL
+Returns a hash reference with the following keys:
 
-billing, not recommended for signups
+=over 4
 
-=item COMP
+=item error
 
-free, definitely not recommended for signups
+Empty on success, or an error message on errors.  
 
-=item PREPAY
+=item pkgnum
 
-special billing type: applies a credit (see FS::prepay_credit) and sets billing type to BILL
+On success, the new pkgnum
 
 =back
 
-=item cvv_enabled
-
-True if CVV features are available (1.5+ or 1.4.2 with CVV schema patch)
 
-=item msgcat
+=item renew_info
 
-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".
+Provides useful info for early renewals.
 
-=item statedefault
+Takes a hash reference as parameter with the following keys:
 
-Default state
+=over 4
 
-=item countrydefault
+=item session_id
 
-Default country
+Session identifier
 
 =back
 
-=item new_customer HASHREF
-
-Creates a new customer.  Takes a hash reference as parameter with the
+Returns a hash reference.  On errors, it contains a single key, B<error>, with
+the error message.  Otherwise, contains a single key, B<dates>, pointing to
+an array refernce of hash references.  Each hash reference contains the
 following keys:
 
 =over 4
 
-=item first
+=item bill_date
 
-first name (required)
+(Future) Bill date.  Indicates a future date for which billing could be run.
+Specified as a integer UNIX timestamp.  Pass this value to the B<order_renew>
+function.
 
-=item last
+=item bill_date_pretty
 
-last name (required)
+(Future) Bill date as a human-readable string.  (Convenience for display;
+subject to change, so best not to parse for the date.)
 
-=item ss
+=item amount
 
-(not typically collected; mostly used for ACH transactions)
+Base amount which will be charged if renewed early as of this date.
 
-=item company
+=item renew_date
 
-Company name
+Renewal date; i.e. even-futher future date at which the customer will be paid
+through if the early renewal is completed with the given B<bill-date>.
+Specified as a integer UNIX timestamp.
 
-=item address1 (required)
+=item renew_date_pretty
 
-Address line one
+Renewal date as a human-readable string.  (Convenience for display;
+subject to change, so best not to parse for the date.)
 
-=item address2
+=item pkgnum
 
-Address line two
+Package that will be renewed.
 
-=item city (required)
+=item expire_date
 
-City
+Expiration date of the package that will be renewed.
 
-=item county
+=item expire_date_pretty
 
-County
+Expiration date of the package that will be renewed, as a human-readable
+string.  (Convenience for display; subject to change, so best not to parse for
+the date.)
 
-=item state (required)
+=back
 
-State
+=item order_renew
 
-=item zip (required)
+Renews this customer early; i.e. runs billing for this customer in advance.
 
-Zip or postal code
+Takes a hash reference as parameter with the following keys:
 
-=item daytime
+=over 4
 
-Daytime phone number
+=item session_id
 
-=item night
+Session identifier
 
-Evening phone number
+=item date
 
-=item fax
+Integer date as returned by the B<renew_info> function, indicating the advance
+date for which to run billing.
 
-Fax number
+=back
 
-=item payby
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
 
-CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
+=item cancel_pkg
 
-=item payinfo
+Cancels a package for this customer.
 
-Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
+Takes a hash reference as parameter with the following keys:
 
-=item paycvv
+=over 4
 
-Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
+=item session_id
 
-=item paydate
+Session identifier
 
-Expiration date for CARD/DCRD
+=item pkgpart
 
-=item payname
+pkgpart of package to cancel
 
-Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=item provision_acct 
+
+Provisions an account (svc_acct).
+
+Takes a hash references as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item pkgnum
+
+pkgnum of package into which this service is provisioned
+
+=item svcpart
+
+svcpart or service definition to provision
+
+=item username
+
+=item domsvc
+
+=item _password
+
+=back
+
+=item provision_phone
+
+Provisions a phone number (svc_phone).
+
+Takes a hash references as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item pkgnum
+
+pkgnum of package into which this service is provisioned
+
+=item svcpart
+
+svcpart or service definition to provision
+
+=item countrycode
+
+=item phonenum
+
+=item address1
+
+=item address2
+
+=item city
+
+=item county
+
+=item state
+
+=item zip
+
+=item country
+
+E911 Address (optional)
+
+=back
+
+=item provision_external
+
+Provisions an external service (svc_external).
+
+Takes a hash references as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item pkgnum
+
+pkgnum of package into which this service is provisioned
+
+=item svcpart
+
+svcpart or service definition to provision
+
+=item id
+
+=item title
+
+=back
+
+=back
+
+=head1 SIGNUP FUNCTIONS
+
+=over 4
+
+=item signup_info HASHREF
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id - Optional agent/reseller interface session
+
+=back
+
+Returns a hash reference containing information that may be useful in
+displaying a signup page.  The hash reference contains the following keys:
+
+=over 4
+
+=item cust_main_county
+
+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.
+
+=item part_pkg
+
+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
+an agentnum specified explicitly via reseller interface session_id in the
+options.
+
+=item agent
+
+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.
+
+=item agentnum2part_pkg
+
+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.
+
+=item svc_acct_pop
+
+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.
+
+=item security_phrase
+
+True if the "security_phrase" feature is enabled
+
+=item payby
+
+Array reference of acceptable payment types for signup
+
+=over 4
+
+=item CARD
+
+credit card - automatic
+
+=item DCRD
+
+credit card - on-demand - version 1.5+ only
+
+=item CHEK
+
+electronic check - automatic
+
+=item DCHK
+
+electronic check - on-demand - version 1.5+ only
+
+=item LECB
+
+Phone bill billing
+
+=item BILL
+
+billing, not recommended for signups
+
+=item COMP
+
+free, definitely not recommended for signups
+
+=item PREPAY
+
+special billing type: applies a credit (see FS::prepay_credit) and sets billing type to BILL
+
+=back
+
+=item cvv_enabled
+
+True if CVV features are available (1.5+ or 1.4.2 with CVV schema patch)
+
+=item msgcat
+
+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".
+
+=item statedefault
+
+Default state
+
+=item countrydefault
+
+Default country
+
+=back
+
+=item new_customer_minimal HASHREF
+
+Creates a new customer.
+
+Current differences from new_customer: An address is not required.  promo_code
+and reg_code are not supported.  If invoicing_list and _password is passed, a
+contact will be created with self-service access (no pkgpart or username is
+necessary).  No initial billing is run (this may change in a future version).
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item first
+
+first name (required)
+
+=item last
+
+last name (required)
+
+=item ss
+
+(not typically collected; mostly used for ACH transactions)
+
+=item company
+
+Company name
+
+=item address1
+
+Address line one
+
+=item address2
+
+Address line two
+
+=item city
+
+City
+
+=item county
+
+County
+
+=item state
+
+State
+
+=item zip
+
+Zip or postal code
+
+=item daytime
+
+Daytime phone number
+
+=item night
+
+Evening phone number
+
+=item fax
+
+Fax number
+
+=item payby
+
+CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
+
+=item payinfo
+
+Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
+
+=item paycvv
+
+Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
+
+=item paydate
+
+Expiration date for CARD/DCRD
+
+=item payname
+
+Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
 
 =item invoicing_list
 
@@ -972,6 +1479,10 @@ comma-separated list of email addresses for email invoices.  The special value '
 
 referring customer number
 
+=item agentnum
+
+Agent number
+
 =item pkgpart
 
 pkgpart of initial package
@@ -992,10 +1503,153 @@ Security phrase
 
 Access number (index, not the literal number)
 
+=item countrycode
+
+Country code (to be provisioned as a service)
+
+=item phonenum
+
+Phone number (to be provisioned as a service)
+
+=item pin
+
+Voicemail PIN
+
+=back
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+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)
+
+=back
+
+=item new_customer HASHREF
+
+Creates a new customer.  Takes a hash reference as parameter with the
+following keys:
+
+=over 4
+
+=item first
+
+first name (required)
+
+=item last
+
+last name (required)
+
+=item ss
+
+(not typically collected; mostly used for ACH transactions)
+
+=item company
+
+Company name
+
+=item address1 (required)
+
+Address line one
+
+=item address2
+
+Address line two
+
+=item city (required)
+
+City
+
+=item county
+
+County
+
+=item state (required)
+
+State
+
+=item zip (required)
+
+Zip or postal code
+
+=item daytime
+
+Daytime phone number
+
+=item night
+
+Evening phone number
+
+=item fax
+
+Fax number
+
+=item payby
+
+CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
+
+=item payinfo
+
+Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
+
+=item paycvv
+
+Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
+
+=item paydate
+
+Expiration date for CARD/DCRD
+
+=item payname
+
+Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
+
+=item invoicing_list
+
+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),
+
+=item referral_custnum
+
+referring customer number
+
 =item agentnum
 
 Agent number
 
+=item pkgpart
+
+pkgpart of initial package
+
+=item username
+
+Username
+
+=item _password
+
+Password
+
+=item sec_phrase
+
+Security phrase
+
+=item popnum
+
+Access number (index, not the literal number)
+
+=item countrycode
+
+Country code (to be provisioned as a service)
+
+=item phonenum
+
+Phone number (to be provisioned as a service)
+
+=item pin
+
+Voicemail PIN
+
 =back
 
 Returns a hash reference with the following keys:
@@ -1143,6 +1797,18 @@ END
   my $county_html = $script_html;
   if ( $countyflag ) {
     $county_html .= qq!<SELECT NAME="${prefix}county" onChange="$param->{'onchange'}">!;
+    foreach my $county ( 
+      sort keys %{ $cust_main_county{$param->{'selected_country'}}{$param->{'selected_state'}} }
+    ) {
+      my $text = $county || '(n/a)';
+      $county_html .= qq!<OPTION VALUE="$county"!.
+                      ($county eq $param->{'selected_county'} ? 
+                        ' SELECTED>' : 
+                        '>'
+                      ).
+                      $text.
+                      '</OPTION>';
+    }
     $county_html .= '</SELECT>';
   } else {
     $county_html .=
@@ -1154,28 +1820,95 @@ END
   foreach my $state ( sort keys %{ $cust_main_county{$param->{'selected_country'}} } ) {
     my $text = $state || '(n/a)';
     my $selected = $state eq $param->{'selected_state'} ? 'SELECTED' : '';
-    $state_html .= "\n<OPTION $selected VALUE=$state>$text</OPTION>"
+    $state_html .= "\n<OPTION $selected VALUE=\"$state\">$text</OPTION>"
   }
   $state_html .= '</SELECT>';
 
-  $state_html .= '</SELECT>';
+  my $country_html = '';
+  if ( scalar( keys %cust_main_county ) > 1 )  {
+
+    $country_html = qq(<SELECT NAME="${prefix}country" ).
+                    qq(onChange="${prefix}country_changed(this); ).
+                                 $param->{'onchange'}.
+                               '"'.
+                      '>';
+    my $countrydefault = $param->{default_country} || 'US';
+    foreach my $country (
+      sort { ($b eq $countrydefault) <=> ($a eq $countrydefault) or $a cmp $b }
+        keys %cust_main_county
+    ) {
+      my $selected = $country eq $param->{'selected_country'}
+                       ? ' SELECTED'
+                       : '';
+      $country_html .= "\n<OPTION $selected>$country</OPTION>"
+    }
+    $country_html .= '</SELECT>';
+  } else {
+
+    $country_html = qq(<INPUT TYPE="hidden" NAME="${prefix}country" ).
+                            ' VALUE="'. (keys %cust_main_county )[0]. '">';
 
-  my $country_html = qq!<SELECT NAME="${prefix}country" !.
-                     qq!onChange="${prefix}country_changed(this); $param->{'onchange'}">!;
-  my $countrydefault = $param->{default_country} || 'US';
-  foreach my $country (
-    sort { ($b eq $countrydefault) <=> ($a eq $countrydefault) or $a cmp $b }
-      keys %cust_main_county
-  ) {
-    my $selected = $country eq $param->{'selected_country'} ? ' SELECTED' : '';
-    $country_html .= "\n<OPTION$selected>$country</OPTION>"
   }
-  $country_html .= '</SELECT>';
 
   ($county_html, $state_html, $country_html);
 
 }
 
+sub regionselector_hashref {
+  my ($county_html, $state_html, $country_html) = regionselector(@_);
+  {
+    'county_html'  => $county_html,
+    'state_html'   => $state_html,
+    'country_html' => $country_html,
+  };
+}
+
+=item location_form HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item session_id
+
+Current customer session_id
+
+=item no_asterisks
+
+Omit red asterisks from required fields.
+
+=item address1_label
+
+Label for first address line.
+
+=back
+
+Returns an HTML fragment for a location form (address, city, state, zip,
+country)
+
+=cut
+
+sub location_form {
+  my $param;
+  if ( ref($_[0]) ) {
+    $param = shift;
+  } else {
+    $param = { @_ };
+  }
+
+  my $session_id = delete $param->{'session_id'};
+
+  my $rv = mason_comp( 'session_id' => $session_id,
+                       'comp'       => '/elements/location.html',
+                       'args'       => [ %$param ],
+                     );
+
+  #hmm.
+  $rv->{'error'} || $rv->{'output'};
+
+}
+
+
 #=item expselect HASHREF | LIST
 #
 #Takes as input a hashref or list of key/value pairs with the following keys:
@@ -1343,6 +2076,8 @@ END
 
   $text .= "}\n</SCRIPT>\n";
 
+  $param->{'acstate'} = '' unless defined($param->{'acstate'});
+
   $text .=
     qq!<TABLE CELLPADDING="0"><TR><TD><SELECT NAME="acstate"! .
     qq!SIZE=1 onChange="acstate_changed(this)"><OPTION VALUE=-1>State!;
@@ -1412,7 +2147,7 @@ sub domainselector {
 
   return '<INPUT TYPE="hidden" NAME="domsvc" VALUE="">'
     unless scalar(keys %$domains);
-    
+
   if (scalar(keys %$domains) == 1) {
     my $key;
     foreach(keys %$domains) {
@@ -1422,8 +2157,9 @@ sub domainselector {
            '<INPUT TYPE="hidden" NAME="domsvc" VALUE="'. $key. '"></TD></TR>'
   }
 
-  my $text .= qq!<TR><TD ALIGN="right">Domain</TD><TD><SELECT NAME="domsvc" SIZE=1 STYLE="width: 20em"><OPTION>(Choose Domain)!;
+  my $text .= qq!<TR><TD ALIGN="right">Domain</TD><TD><SELECT NAME="domsvc" SIZE=1 STYLE="width: 20em">!;
 
+  $text .= '<OPTION>(Choose Domain)' unless $domsvc;
 
   foreach my $domain ( sort { $domains->{$a} cmp $domains->{$b} } keys %$domains ) {
     $text .= qq!<OPTION VALUE="!. $domain. '"'.
@@ -1437,6 +2173,43 @@ sub domainselector {
 
 }
 
+=item didselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item field
+
+Field name for the returned HTML fragment.
+
+=item svcpart
+
+Service definition (see L<FS::part_svc>)
+
+=back
+
+Returns an HTML fragment for DID selection.
+
+=cut
+
+sub didselector {
+  my $param;
+  if ( ref($_[0]) ) {
+    $param = shift;
+  } else {
+    $param = { @_ };
+  }
+
+  my $rv = mason_comp( 'comp'=>'/elements/select-did.html',
+                       'args'=>[ %$param ],
+                     );
+
+  #hmm.
+  $rv->{'error'} || $rv->{'output'};
+
+}
+
 =back
 
 =head1 RESELLER FUNCTIONS
@@ -1445,14 +2218,23 @@ Note: Resellers can also use the B<signup_info> and B<new_customer> functions
 with their active session, and the B<customer_info> and B<order_pkg> functions
 with their active session and an additional I<custnum> parameter.
 
+For the most part, development of the reseller web interface has been
+superceded by agent-virtualized access to the backend.
+
 =over 4
 
 =item agent_login
 
+Agent login
+
 =item agent_info
 
+Agent info
+
 =item agent_list_customers
 
+List agent's customers.
+
 =back
 
 =head1 BUGS