Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / fs_selfservice / FS-SelfService / SelfService.pm
index 216e372..8227e57 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;
@@ -21,38 +22,104 @@ $socket .= '.'.$tag if defined $tag && length($tag);
 
 #maybe should ask ClientAPI for this list
 %autoload = (
-  'passwd'               => 'passwd/passwd',
-  'chfn'                 => 'passwd/passwd',
-  'chsh'                 => 'passwd/passwd',
-  'login'                => 'MyAccount/login',
-  'logout'               => 'MyAccount/logout',
-  'customer_info'        => 'MyAccount/customer_info',
-  'edit_info'            => 'MyAccount/edit_info',     #add to ss cgi!
-  'invoice'              => 'MyAccount/invoice',
-  'invoice_logo'         => 'MyAccount/invoice_logo',
-  'list_invoices'        => 'MyAccount/list_invoices', #?
-  'cancel'               => 'MyAccount/cancel',        #add to ss cgi!
-  'payment_info'         => 'MyAccount/payment_info',
-  'process_payment'      => 'MyAccount/process_payment',
-  'process_prepay'       => 'MyAccount/process_prepay',
-  'list_pkgs'            => 'MyAccount/list_pkgs',     #add to ss cgi (added?)
-  'list_svcs'            => 'MyAccount/list_svcs',     #add to ss cgi (added?)
-  'order_pkg'            => 'MyAccount/order_pkg',     #add to ss cgi!
-  'cancel_pkg'           => 'MyAccount/cancel_pkg',    #add to ss cgi!
-  'charge'               => 'MyAccount/charge',        #?
-  'part_svc_info'        => 'MyAccount/part_svc_info',
-  'provision_acct'       => 'MyAccount/provision_acct',
-  'provision_external'   => 'MyAccount/provision_external',
-  'unprovision_svc'      => 'MyAccount/unprovision_svc',
-  'myaccount_passwd'     => 'MyAccount/myaccount_passwd',
-  'signup_info'          => 'Signup/signup_info',
-  'new_customer'         => 'Signup/new_customer',
-  'agent_login'          => 'Agent/agent_login',
-  'agent_logout'         => 'Agent/agent_logout',
-  'agent_info'           => 'Agent/agent_info',
-  'agent_list_customers' => 'Agent/agent_list_customers',
+  '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',
+  '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',
+  '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',
+);
+@EXPORT_OK = (
+  keys(%autoload),
+  qw( regionselector regionselector_hashref location_form
+      expselect popselector domainselector didselector
+    )
 );
-@EXPORT_OK = ( keys(%autoload), qw( regionselector expselect popselector ) );
 
 $ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin';
 $ENV{'SHELL'} = '/bin/sh';
@@ -61,8 +128,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!";
@@ -186,11 +256,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,
                       }
                     );
   
@@ -235,10 +310,16 @@ following keys:
 
 =item username
 
+Username
+
 =item domain
 
+Domain
+
 =item password
 
+Password
+
 =back
 
 Returns a hash reference with the following keys:
@@ -282,7 +363,9 @@ the following keys: invnum, date, owed
 
 An HTML fragment containing shipping and billing addresses.
 
-=item The following fields are also returned: 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
+=item The following fields are also returned
+
+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
 
 =back
 
@@ -386,14 +469,24 @@ Exact name on credit card (CARD/DCRD)
 
 =item address1
 
+Address line one
+
 =item address2
 
+Address line two
+
 =item city
 
+City
+
 =item state
 
+State
+
 =item zip
 
+Zip or postal code
+
 =item payby
 
 Customer's current default payment type.
@@ -427,10 +520,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
 
@@ -443,6 +540,12 @@ hash reference as parameter with the following keys:
 
 =item session_id
 
+Session identifier
+
+=item amount
+
+Amount
+
 =item save
 
 If true, address and card information entered will be saved for subsequent
@@ -456,16 +559,32 @@ payby to DCRD).  This option only has meaning if B<save> is set true.
 
 =item payname
 
+Name on card
+
 =item address1
 
+Address line one
+
 =item address2
 
+Address line two
+
 =item city
 
+City
+
 =item state
 
+State
+
 =item zip
 
+Zip or postal code
+
+=item country
+
+Two-letter country code
+
 =item payinfo
 
 Card number
@@ -478,19 +597,52 @@ 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
 
-Returns package information for this customer.
+Returns package information for this customer.  For more detail on services,
+see L</list_svcs>.
 
 Takes a hash reference as parameter with a single key: B<session_id>
 
@@ -498,6 +650,13 @@ Returns a hash reference containing customer package information.  The hash refe
 
 =over 4
 
+=item custnum
+
+Customer number
+
+=item error
+
+Empty on success, or an error message on errors.
 
 =item cust_pkg HASHREF
 
@@ -505,21 +664,155 @@ Array reference of hash references, each of which has the fields of a cust_pkg
 record (see L<FS::cust_pkg>) as well as the fields below.  Note these are not
 the internal FS:: objects, but hash references of columns and values.
 
-=item all fields of part_pkg (XXXpare this down to a secure subset)
+=over 4
+
+=item part_pkg fields
+
+All fields of part_pkg for this specific cust_pkg (be careful with this
+information - it may reveal more about your available packages than you would
+like users to know in aggregate) 
+
+=cut
+
+#XXX pare part_pkg fields down to a more secure subset
+
+=item part_svc
 
-=item part_svc - An array of hash references, each of which has the following keys:
+An array of hash references indicating information on unprovisioned services
+available for provisioning for this specific cust_pkg.  Each has the following
+keys:
 
 =over 4
 
-=item all fields of part_svc (XXXpare this down to a secure subset)
+=item part_svc fields
 
-=item avail
+All fields of part_svc (be careful with this information - it may reveal more
+about your available packages than you would like users to know in aggregate) 
+
+=cut
+
+#XXX pare part_svc fields down to a more secure subset
 
 =back
 
-=item error
+=item cust_svc
 
-Empty on success, or an error message on errors.
+An array of hash references indicating information on the customer services
+already provisioned for this specific cust_pkg.  Each has the following keys:
+
+=over 4
+
+=item label
+
+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
+
+=item svcnum
+
+Primary key for this service
+
+=item svcpart
+
+Service definition (see L<FS::part_svc>)
+
+=item pkgnum
+
+Customer package (see L<FS::cust_pkg>)
+
+=item overlimit
+
+Blank if the service is not over limit, or the date the service exceeded its usage limit (as a UNIX timestamp).
+
+=back
+
+=back
+
+=item list_svcs
+
+Returns service information for this customer.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference containing customer package information.  The hash reference contains the following keys:
+
+=over 4
+
+=item custnum
+
+Customer number
+
+=item svcs
+
+An array of hash references indicating information on all of this customer's
+services.  Each has the following keys:
+
+=over 4
+
+=item svcnum
+
+Primary key for this service
+
+=item label
+
+Name of this service
+
+=item value
+
+Meaningful user-specific identifier for the service (i.e. username, domain, or
+mail alias).
+
+=back
+
+Account (svc_acct) services also have the following keys:
+
+=over 4
+
+=item username
+
+Username
+
+=item email
+
+username@domain
+
+=item seconds
+
+Seconds remaining
+
+=item upbytes
+
+Upload bytes remaining
+
+=item downbytes
+
+Download bytes remaining
+
+=item totalbytes
+
+Total bytes remaining
+
+=item recharge_amount
+
+Cost of a recharge
+
+=item recharge_seconds
+
+Number of seconds gained by recharge
+
+=item recharge_upbytes
+
+Number of upload bytes gained by recharge
+
+=item recharge_downbytes
+
+Number of download bytes gained by recharge
+
+=item recharge_totalbytes
+
+Number of total bytes gained by recharge
+
+=back
 
 =back
 
@@ -533,28 +826,227 @@ Takes a hash reference as parameter with the following keys:
 
 =item session_id
 
+Session identifier
+
 =item pkgpart
 
+Package to order (see L<FS::part_pkg>).
+
 =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
 
+Username
+
 =item _password
 
+Password
+
 =item sec_phrase
 
+Optional security phrase
+
 =item popnum
 
+Optional Access number number
+
+=back
+
+Fields used when provisioning an svc_domain service:
+
+=over 4
+
+=item domain
+
+Domain
+
+=back
+
+Fields used when provisioning an svc_phone service:
+
+=over 4
+
+=item phonenum
+
+Phone number
+
+=item pin
+
+Voicemail PIN
+
+=item sip_password
+
+SIP password
+
+=back
+
+Fields used when provisioning an svc_external service:
+
+=over 4
+
+=item id
+
+External numeric ID.
+
+=item title
+
+External text title.
+
+=back
+
+Fields used when provisioning an svc_pbx service:
+
+=over 4
+
+=item id
+
+Numeric ID.
+
+=item name
+
+Text name.
+
 =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.
 
+=item change_pkg
+
+Changes a package for this customer.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item pkgnum
+
+Existing customer package.
+
+=item pkgpart
+
+New package to order (see L<FS::part_pkg>).
+
+=back
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors.  
+
+=item pkgnum
+
+On success, the new pkgnum
+
+=back
+
+
+=item renew_info
+
+Provides useful info for early renewals.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=back
+
+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 bill_date
+
+(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 bill_date_pretty
+
+(Future) Bill date as a human-readable string.  (Convenience for display;
+subject to change, so best not to parse for the date.)
+
+=item amount
+
+Base amount which will be charged if renewed early as of this date.
+
+=item renew_date
+
+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 renew_date_pretty
+
+Renewal date as a human-readable string.  (Convenience for display;
+subject to change, so best not to parse for the date.)
+
+=item pkgnum
+
+Package that will be renewed.
+
+=item expire_date
+
+Expiration date of the package that will be renewed.
+
+=item expire_date_pretty
+
+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.)
+
+=back
+
+=item order_renew
+
+Renews this customer early; i.e. runs billing for this customer in advance.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item date
+
+Integer date as returned by the B<renew_info> function, indicating the advance
+date for which to run billing.
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
 =item cancel_pkg
 
 Cancels a package for this customer.
@@ -565,8 +1057,12 @@ Takes a hash reference as parameter with the following keys:
 
 =item session_id
 
+Session identifier
+
 =item pkgpart
 
+pkgpart of package to cancel
+
 =back
 
 Returns a hash reference with a single key, B<error>, empty on success, or an
@@ -625,21 +1121,37 @@ Array reference of acceptable payment types for signup
 
 =over 4
 
-=item CARD (credit card - automatic)
+=item CARD
+
+credit card - automatic
+
+=item DCRD
 
-=item DCRD (credit card - on-demand - version 1.5+ only)
+credit card - on-demand - version 1.5+ only
 
-=item CHEK (electronic check - automatic)
+=item CHEK
 
-=item DCHK (electronic check - on-demand - version 1.5+ only)
+electronic check - automatic
 
-=item LECB (Phone bill billing)
+=item DCHK
 
-=item BILL (billing, not recommended for signups)
+electronic check - on-demand - version 1.5+ only
 
-=item COMP (free, definately not recommended for signups)
+=item LECB
 
-=item PREPAY (special billing type: applies a credit (see FS::prepay_credit) and sets billing type to BILL)
+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
 
@@ -668,57 +1180,121 @@ following keys:
 
 =over 4
 
-=item first - first name (required)
+=item first
+
+first name (required)
 
-=item last - last name (required)
+=item last
 
-=item ss (not typically collected; mostly used for ACH transactions)
+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)
 
-=item daytime - phone
+Zip or postal code
+
+=item daytime
 
-=item night - phone
+Daytime phone number
 
-=item fax - phone
+=item night
 
-=item payby - CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
+Evening phone number
 
-=item payinfo - Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
+=item fax
 
-=item paycvv - Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
+Fax number
+
+=item payby
+
+CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
+
+=item payinfo
 
-=item paydate - Expiration date for CARD/DCRD
+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
 
-=item payname - Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
+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 invoicing_list
 
-=item referral_custnum - referring customer number
+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 pkgpart - pkgpart of initial package
+=item referral_custnum
+
+referring customer number
+
+=item agentnum
+
+Agent number
+
+=item pkgpart
+
+pkgpart of initial package
 
 =item username
 
+Username
+
 =item _password
 
-=item sec_phrase - security phrase
+Password
+
+=item sec_phrase
+
+Security phrase
+
+=item popnum
+
+Access number (index, not the literal number)
 
-=item popnum - access number (index, not the literal number)
+=item countrycode
 
-=item agentnum - agent number
+Country code (to be provisioned as a service)
+
+=item phonenum
+
+Phone number (to be provisioned as a service)
+
+=item pin
+
+Voicemail PIN
 
 =back
 
@@ -726,7 +1302,9 @@ 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 Sysadmin | View/Edit message catalog)
+=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
 
@@ -738,19 +1316,35 @@ Takes as input a hashref or list of key/value pairs with the following keys:
 
 =item selected_county
 
+Currently selected county
+
 =item selected_state
 
+Currently selected state
+
 =item selected_country
 
-=item prefix - Specify a unique prefix string  if you intend to use the HTML output multiple time son one page.
+Currently selected country
+
+=item prefix
+
+Specify a unique prefix string  if you intend to use the HTML output multiple time son one page.
 
-=item onchange - Specify a javascript subroutine to call on changes
+=item onchange
+
+Specify a javascript subroutine to call on changes
 
 =item default_state
 
+Default state
+
 =item default_country
 
-=item locales - 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>.
+Default country
+
+=item locales
+
+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>.
 
 =back
 
@@ -849,6 +1443,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 .=
@@ -864,24 +1470,91 @@ END
   }
   $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:
@@ -948,7 +1621,11 @@ Takes as input a hashref or list of key/value pairs with the following keys:
 
 =item popnum
 
-=item pops - 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>.
+Access number number
+
+=item pops
+
+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>.
 
 =back
 
@@ -1045,6 +1722,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!;
@@ -1079,6 +1758,104 @@ END
 
 }
 
+=item domainselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item pkgnum
+
+Package number
+
+=item domsvc
+
+Service number of the selected item.
+
+=back
+
+Returns an HTML fragment for domain selection.
+
+=cut
+
+sub domainselector {
+  my $param;
+  if ( ref($_[0]) ) {
+    $param = shift;
+  } else {
+    $param = { @_ };
+  }
+  my $domsvc= $param->{'domsvc'};
+  my $rv = 
+      domain_select_hash(map {$_ => $param->{$_}} qw(pkgnum svcpart pkgpart) );
+  my $domains = $rv->{'domains'};
+  $domsvc = $rv->{'domsvc'} unless $domsvc;
+
+  return '<INPUT TYPE="hidden" NAME="domsvc" VALUE="">'
+    unless scalar(keys %$domains);
+
+  if (scalar(keys %$domains) == 1) {
+    my $key;
+    foreach(keys %$domains) {
+      $key = $_;
+    }
+    return '<TR><TD ALIGN="right">Domain</TD><TD>'. $domains->{$key}.
+           '<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">!;
+
+  $text .= '<OPTION>(Choose Domain)' unless $domsvc;
+
+  foreach my $domain ( sort { $domains->{$a} cmp $domains->{$b} } keys %$domains ) {
+    $text .= qq!<OPTION VALUE="!. $domain. '"'.
+             ( ( $domsvc && $domain == $domsvc ) ? ' SELECTED' : '' ). ">".
+             $domains->{$domain};
+  }
+
+  $text .= qq!</SELECT></TD></TR>!;
+
+  $text;
+
+}
+
+=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
@@ -1087,14 +1864,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