diff options
Diffstat (limited to 'httemplate/edit')
59 files changed, 2474 insertions, 1162 deletions
diff --git a/httemplate/edit/REAL_cust_pkg.cgi b/httemplate/edit/REAL_cust_pkg.cgi index b2c89c3..5752c8d 100755 --- a/httemplate/edit/REAL_cust_pkg.cgi +++ b/httemplate/edit/REAL_cust_pkg.cgi @@ -32,6 +32,11 @@ </TR> <TR> + <TD ALIGN="right">Custom</TD> + <TD BGCOLOR="#ffffff"><% $part_pkg->custom %></TD> + </TR> + + <TR> <TD ALIGN="right">Comment</TD> <TD BGCOLOR="#ffffff"><% $part_pkg->comment %></TD> </TR> @@ -41,6 +46,7 @@ <TD BGCOLOR="#ffffff"><% $cust_pkg->otaker %></TD> </TR> + <& .row_edit, cust_pkg=>$cust_pkg, column=>'start_date', label=>'Start' &> <& .row_edit, cust_pkg=>$cust_pkg, column=>'setup', label=>'Setup' &> <& .row_edit, cust_pkg=>$cust_pkg, column=>'last_bill', label=>$last_bill_or_renewed &> <& .row_edit, cust_pkg=>$cust_pkg, column=>'bill', label=>$next_bill_or_prepaid_until &> diff --git a/httemplate/edit/agent.cgi b/httemplate/edit/agent.cgi index 215542d..a0af9fa 100755 --- a/httemplate/edit/agent.cgi +++ b/httemplate/edit/agent.cgi @@ -46,13 +46,21 @@ Agent #<% $agent->agentnum ? $agent->agentnum : "(NEW)" %> <TD><INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $agent->disabled eq 'Y' ? ' CHECKED' : '' %>></TD> </TR> +% if ( $conf->exists('agent-invoice_template') ) { + <% include('/elements/tr-select-invoice_template.html', 'label' => 'Invoice template', 'field' => 'invoice_template', 'curr_value' => $agent->invoice_template, ) %> - + +% } else { + + <INPUT TYPE="hidden" NAME="invoice_template" VALUE="<% $agent->invoice_template %>"> + +% } + % if ( $conf->config('ticket_system') ) { % my $default_queueid = $conf->config('ticket_system-default_queueid'); % my $default_queue = FS::TicketSystem->queue($default_queueid); diff --git a/httemplate/edit/agent_type.cgi b/httemplate/edit/agent_type.cgi index abf4bf8..8a6fbc2 100755 --- a/httemplate/edit/agent_type.cgi +++ b/httemplate/edit/agent_type.cgi @@ -20,7 +20,7 @@ Select which packages agents of this type may sell to customers<BR> 'source_obj' => $agent_type, 'link_table' => 'type_pkgs', 'target_table' => 'part_pkg', - 'name_callback' => sub { $_[0]->pkg. ' - '. $_[0]->comment; }, + 'name_callback' => sub { $_[0]->pkg_comment(nopkgpart => 1); }, 'target_link' => $p.'edit/part_pkg.cgi?', 'disable-able' => 1, diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi index c9ca31f..5785a05 100755 --- a/httemplate/edit/cust_credit.cgi +++ b/httemplate/edit/cust_credit.cgi @@ -40,6 +40,16 @@ Credit <TD><SELECT NAME="apply"><OPTION VALUE="yes" SELECTED>yes<OPTION>no</SELECT></TD> </TR> +% if ( $conf->exists('pkg-balances') ) { + <% include('/elements/tr-select-cust_pkg-balances.html', + 'custnum' => $custnum, + 'cgi' => $cgi + ) + %> +% } else { + <INPUT TYPE="hidden" NAME="pkgnum" VALUE=""> +% } + </TABLE> <BR> diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index d3004f1..15c9f45 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -1,14 +1,18 @@ <% include('/elements/header.html', "Customer $action", '', - ' onUnload="myclose()"' + ' onUnload="myclose()"' #hmm, in billing.html ) %> -<% include('/elements/init_overlib.html') %> - <% include('/elements/error.html') %> -<FORM NAME="topform" STYLE="margin-bottom: 0"> +<FORM NAME = "CustomerForm" + METHOD = "POST" + ACTION = "<% popurl(1) %>process/cust_main.cgi" +%# STYLE = "margin-bottom: 0" +%# STYLE="margin-top: 0; margin-bottom: 0"> +> + <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> % if ( $custnum ) { @@ -19,101 +23,25 @@ <BR><BR> % } -<% &ntable("#cccccc") %> - -%# agent -<% include('/elements/tr-select-agent.html', - 'curr_value' => $cust_main->agentnum, - 'label' => "<B>${r}Agent</B>", - 'empty_label' => 'Select agent', - 'disable_empty' => ( $cust_main->agentnum ? 1 : 0 ), - ) -%> - -%# agent_custid -% if ( $conf->exists('cust_main-edit_agent_custid') ) { - - <TR> - <TD ALIGN="right">Customer identifier</TD> - <TD><INPUT TYPE="text" NAME="agent_custid" VALUE="<% $cust_main->agent_custid %>"></TD> - </TR> - -% } else { - - <INPUT TYPE="hidden" NAME="agent_custid" VALUE="<% $cust_main->agent_custid %>"> - -% } - -%# referral (advertising source) -%my $refnum = $cust_main->refnum || $conf->config('referraldefault') || 0; -%if ( $custnum && ! $conf->exists('editreferrals') ) { - - <INPUT TYPE="hidden" NAME="refnum" VALUE="<% $refnum %>"> - -% } else { - - <% include('/elements/tr-select-part_referral.html', - 'curr_value' => $refnum - ) - %> -% } - - -%# referring customer -%my $referring_cust_main = ''; -%if ( $cust_main->referral_custnum -% and $referring_cust_main = -% qsearchs('cust_main', { custnum => $cust_main->referral_custnum } ) -%) { - - <TR> - <TD ALIGN="right">Referring customer</TD> - <TD> - <A HREF="<% popurl(1) %>/cust_main.cgi?<% $cust_main->referral_custnum %>"><% $cust_main->referral_custnum %>: <% $referring_cust_main->name %></A> - </TD> - </TR> - <INPUT TYPE="hidden" NAME="referral_custnum" VALUE="<% $cust_main->referral_custnum %>"> -% } elsif ( ! $conf->exists('disable_customer_referrals') ) { - - - <TR> - <TD ALIGN="right">Referring customer</TD> - <TD> - <!-- <INPUT TYPE="text" NAME="referral_custnum" VALUE=""> --> - <% include('/elements/search-cust_main.html', - 'field_name' => 'referral_custnum', - ) - %> - </TD> - </TR> -% } else { - - - <INPUT TYPE="hidden" NAME="referral_custnum" VALUE=""> -% } - - -</TABLE> - -<!-- birthdate --> +%# agent, agent_custid, refnum (advertising source), referral_custnum +<% include('cust_main/top_misc.html', $cust_main, 'custnum' => $custnum ) %> +%# birthdate % if ( $conf->exists('cust_main-enable_birthdate') ) { - <BR> - <% ntable("#cccccc", 2) %> - <% include ('/elements/tr-input-date-field.html', - 'birthdate', - $cust_main->birthdate, - 'Date of Birth', - $conf->config('date_format') || "%m/%d/%Y", - 1) - %> - - </TABLE> + <% include('cust_main/birthdate.html', $cust_main) %> +% } +%# latitude and longitude +% if ( $conf->exists('cust_main-require_censustract') ) { +% my ($latitude, $longitude) = $cust_main->service_coordinates; +% $latitude ||= $conf->config('company_latitude') || ''; +% $longitude ||= $conf->config('company_longitude') || ''; + <INPUT NAME="latitude" TYPE="hidden" VALUE="<% $latitude |h %>"> + <INPUT NAME="longitude" TYPE="hidden" VALUE="<% $longitude |h %>"> % } -<!-- contact info --> +%# contact info % my $same_checked = ''; % my $ship_disabled = ''; @@ -128,8 +56,9 @@ % } % } -<BR><BR> -Billing address +<BR> +<FONT SIZE="+1"><B>Billing address</B></FONT> + <% include('cust_main/contact.html', 'cust_main' => $cust_main, 'pre' => '', @@ -199,7 +128,8 @@ function samechanged(what) { </SCRIPT> <BR> -Service address +<FONT SIZE="+1"><B>Service address</B></FONT> + (<INPUT TYPE="checkbox" NAME="same" VALUE="Y" onClick="samechanged(this)" <%$same_checked%>>same as billing address) <% include('cust_main/contact.html', 'cust_main' => $cust_main, @@ -209,528 +139,133 @@ Service address ) %> - -<!-- billing info --> - +%# billing info <% include( 'cust_main/billing.html', $cust_main, 'payinfo' => $payinfo, 'invoicing_list' => \@invoicing_list, ) %> -<% include( '/elements/xmlhttp.html', - 'url' => $p.'misc/xmlhttp-cust_main-address_standardize.html', - 'subs' => [ 'address_standardize' ], - #'method' => 'POST', #could get too long? - ) -%> - -<SCRIPT> -function bottomfixup(what) { - - //i don't think we need to copy things between two forms anymore, modern - //browsers are fine with DIVs inside FORMs - - var topvars = new Array( - 'birthdate', - - 'custnum', 'agentnum', 'agent_custid', 'refnum', 'referral_custnum', - - 'last', 'first', 'ss', 'company', - 'address1', 'address2', 'city', - 'county', 'state', 'zip', 'country', - 'daytime', 'night', 'fax', - 'stateid', 'stateid_state', - - 'same', - - 'ship_last', 'ship_first', 'ship_company', - 'ship_address1', 'ship_address2', 'ship_city', - 'ship_county', 'ship_state', 'ship_zip', 'ship_country', - 'ship_daytime','ship_night', 'ship_fax', - - 'geocode', - - 'select' // XXX key - ); - - var layervars = new Array( - 'payauto', - 'payinfo', 'payinfo1', 'payinfo2', 'paytype', - 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', - 'paystart_month', 'paystart_year', 'payissue', - 'payip', - 'paid' - ); - - var billing_bottomvars = new Array( - 'tax', - 'invoicing_list', 'invoicing_list_POST', 'invoicing_list_FAX', - 'invoice_terms', - 'spool_cdr', - 'squelch_cdr' - ); - - for ( f=0; f < topvars.length; f++ ) { - var field = topvars[f]; - copyelement( document.topform.elements[field], - document.bottomform.elements[field] - ); - } - - var layerform = document.topform.select.options[document.topform.select.selectedIndex].value; - for ( f=0; f < layervars.length; f++ ) { - var field = layervars[f]; - copyelement( document.forms[layerform].elements[field], - document.bottomform.elements[field] - ); - } - - for ( f=0; f < billing_bottomvars.length; f++ ) { - var field = billing_bottomvars[f]; - copyelement( document.billing_bottomform.elements[field], - document.bottomform.elements[field] - ); - } - - //this part does USPS address correction - - // XXX should this be first and should we update the form fields that are - // displayed??? - - //var state_el = document.bottomform.elements['state']; - - //address_standardize( - var cust_main = new Array( - 'company', document.bottomform.elements['company'].value, - 'address1', document.bottomform.elements['address1'].value, - 'address2', document.bottomform.elements['address2'].value, - 'city', document.bottomform.elements['city'].value, - 'state', document.bottomform.elements['state'].value, - //'state', state_el.options[ state_el.selectedIndex ].value, - 'zip', document.bottomform.elements['zip'].value, - - 'ship_company', document.bottomform.elements['ship_company'].value, - 'ship_address1', document.bottomform.elements['ship_address1'].value, - 'ship_address2', document.bottomform.elements['ship_address2'].value, - 'ship_city', document.bottomform.elements['ship_city'].value, - 'ship_state', document.bottomform.elements['ship_state'].value, - //'ship_state', state_el.options[ state_el.selectedIndex ].value, - 'ship_zip', document.bottomform.elements['ship_zip'].value - ); - - address_standardize( cust_main, update_address ); - -} - -var standardize_address; - -function update_address(arg) { - - var argsHash = eval('(' + arg + ')'); - - var changed = argsHash['address_standardized']; - var ship_changed = argsHash['ship_address_standardized']; - var error = argsHash['error']; - var ship_error = argsHash['ship_error']; - - //yay closures - standardize_address = function () { - - if ( changed ) { - document.bottomform.elements['company'].value = argsHash['new_company']; - document.bottomform.elements['address1'].value = argsHash['new_address1']; - document.bottomform.elements['address2'].value = argsHash['new_address2']; - document.bottomform.elements['city'].value = argsHash['new_city']; - document.bottomform.elements['state'].value = argsHash['new_state']; - //'state', state_el.options[ state_el.selectedIndex ].value, - document.bottomform.elements['zip'].value = argsHash['new_zip']; - } - - if ( ship_changed ) { - document.bottomform.elements['ship_company'].value = argsHash['new_ship_company']; - document.bottomform.elements['ship_address1'].value = argsHash['new_ship_address1']; - document.bottomform.elements['ship_address2'].value = argsHash['new_ship_address2']; - document.bottomform.elements['ship_city'].value = argsHash['new_ship_city']; - document.bottomform.elements['ship_state'].value = argsHash['new_ship_state']; - //'state', state_el.options[ state_el.selectedIndex ].value, - document.bottomform.elements['ship_zip'].value = argsHash['new_ship_zip']; - } - - } - -% if ( $conf->exists('enable_taxproducts') ) { - - if ( <% $taxpre %>error ) { - - if ( document.bottomform.elements['country'].value == 'CA' || - document.bottomform.elements['country'].value == 'US' - ) - { - - var url = "cust_main/choose_tax_location.html?data_vendor=cch-zip;city="+document.bottomform.elements['city'].value+";state="+document.bottomform.elements['state'].value+";zip="+document.bottomform.elements['zip'].value+";country="+document.bottomform.elements['country'].value+";"; - // popup a chooser - OLgetAJAX( url, update_geocode, 300 ); - - } else { - - document.bottomform.elements['geocode'].value = 'DEFAULT'; - document.bottomform.submit(); - - } +% my $ro_comments = $conf->exists('cust_main-use_comments')?'':'readonly'; +% if (!$ro_comments || $cust_main->comments) { - } else + <BR>Comments + <% &ntable("#cccccc") %> + <TR> + <TD> + <TEXTAREA NAME = "comments" + COLS = 80 + ROWS = 5 + WRAP = "HARD" + <% $ro_comments %> + ><% $cust_main->comments %></TEXTAREA> + </TD> + </TR> + </TABLE> % } - if ( changed || ship_changed ) { - -% if ( $conf->exists('cust_main-auto_standardize_address') ) { - - standardize_address(); - document.bottomform.submit(); - -% } else { - - // popup a confirmation popup - - var confirm_change = - '<CENTER><BR><B>Confirm address standardization</B><BR><BR>' + - '<TABLE>'; - - if ( changed ) { - - confirm_change = confirm_change + - '<TR><TH>Entered billing address</TH>' + - '<TH>Standardized billing address</TH></TR>'; - // + '<TR><TD> </TD><TD> </TD></TR>'; - - if ( argsHash['company'] || argsHash['new_company'] ) { - confirm_change = confirm_change + - '<TR><TD>' + argsHash['company'] + - '</TD><TD>' + argsHash['new_company'] + '</TD></TR>'; - } - - confirm_change = confirm_change + - '<TR><TD>' + argsHash['address1'] + - '</TD><TD>' + argsHash['new_address1'] + '</TD></TR>' + - '<TR><TD>' + argsHash['address2'] + - '</TD><TD>' + argsHash['new_address2'] + '</TD></TR>' + - '<TR><TD>' + argsHash['city'] + ', ' + argsHash['state'] + ' ' + argsHash['zip'] + - '</TD><TD>' + argsHash['new_city'] + ', ' + argsHash['new_state'] + ' ' + argsHash['new_zip'] + '</TD></TR>' + - '<TR><TD> </TD><TD> </TD></TR>'; - - } - - if ( ship_changed ) { - - confirm_change = confirm_change + - '<TR><TH>Entered service address</TH>' + - '<TH>Standardized service address</TH></TR>'; - // + '<TR><TD> </TD><TD> </TD></TR>'; - - if ( argsHash['ship_company'] || argsHash['new_ship_company'] ) { - confirm_change = confirm_change + - '<TR><TD>' + argsHash['ship_company'] + - '</TD><TD>' + argsHash['new_ship_company'] + '</TD></TR>'; - } - - confirm_change = confirm_change + - '<TR><TD>' + argsHash['ship_address1'] + - '</TD><TD>' + argsHash['new_ship_address1'] + '</TD></TR>' + - '<TR><TD>' + argsHash['ship_address2'] + - '</TD><TD>' + argsHash['new_ship_address2'] + '</TD></TR>' + - '<TR><TD>' + argsHash['ship_city'] + ', ' + argsHash['ship_state'] + ' ' + argsHash['ship_zip'] + - '</TD><TD>' + argsHash['new_ship_city'] + ', ' + argsHash['new_ship_state'] + ' ' + argsHash['new_ship_zip'] + '</TD></TR>' + - '<TR><TD> </TD><TD> </TD></TR>'; - - } - - var addresses = 'address'; - var height = 268; - if ( changed && ship_changed ) { - addresses = 'addresses'; - height = 396; // #what - } - - confirm_change = confirm_change + - '<TR><TD>' + - '<BUTTON TYPE="button" onClick="document.bottomform.submit();"><IMG SRC="<%$p%>images/error.png" ALT=""> Use entered ' + addresses + '</BUTTON>' + - '</TD><TD>' + - '<BUTTON TYPE="button" onClick="standardize_address(); document.bottomform.submit();"><IMG SRC="<%$p%>images/tick.png" ALT=""> Use standardized ' + addresses + '</BUTTON>' + - '</TD></TR>' + - '<TR><TD COLSPAN=2 ALIGN="center">' + - '<BUTTON TYPE="button" onClick="document.bottomform.submitButton.disabled=false; parent.cClick();"><IMG SRC="<%$p%>images/cross.png" ALT=""> Cancel submission</BUTTON></TD></TR>' + - - '</TABLE></CENTER>'; - - overlib( confirm_change, CAPTION, 'Confirm address standardization', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, height, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); - -% } - - } else { - - document.bottomform.submit(); +% unless ( $custnum ) { - } - -} - -function update_geocode() { - - //yay closures - set_geocode = function (what) { - - //alert(what.options[what.selectedIndex].value); - var argsHash = eval('(' + what.options[what.selectedIndex].value + ')'); - document.bottomform.elements['city'].value = argsHash['city']; - document.bottomform.elements['state'].value = argsHash['state']; - document.bottomform.elements['zip'].value = argsHash['zip']; - document.bottomform.elements['geocode'].value = argsHash['geocode']; - - } - - // popup a chooser - - overlib( OLresponseAJAX, CAPTION, 'Select tax location', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); - -} + <% include('cust_main/first_pkg.html', $cust_main, + 'pkgpart_svcpart' => $pkgpart_svcpart, + #svc_acct + 'username' => $username, + 'password' => $password, + 'popnum' => $popnum, + 'saved_domsvc' => $saved_domsvc, + %svc_phone, + ) + %> -function copyelement(from, to) { - if ( from == undefined ) { - to.value = ''; - } else if ( from.type == 'select-one' ) { - to.value = from.options[from.selectedIndex].value; - //alert(from + " (" + from.type + "): " + to.name + " => (" + from.selectedIndex + ") " + to.value); - } else if ( from.type == 'checkbox' ) { - if ( from.checked ) { - to.value = from.value; - } else { - to.value = ''; - } - } else { - if ( from.value == undefined ) { - to.value = ''; - } else { - to.value = from.value; - } - } - //alert(from + " (" + from.type + "): " + to.name + " => " + to.value); -} +% } -</SCRIPT> +<INPUT TYPE="hidden" NAME="otaker" VALUE="<% $cust_main->otaker %>"> -<FORM ACTION="<% popurl(1) %>process/cust_main.cgi" METHOD=POST NAME="bottomform" STYLE="margin-top: 0; margin-bottom: 0"> +%# cust_main/bottomfixup.js % foreach my $hidden ( -% 'birthdate', -% -% 'custnum', 'agentnum', 'agent_custid', 'refnum', 'referral_custnum', -% 'last', 'first', 'ss', 'company', -% 'address1', 'address2', 'city', -% 'county', 'state', 'zip', 'country', -% 'daytime', 'night', 'fax', -% 'stateid', 'stateid_state', -% -% 'same', -% -% 'ship_last', 'ship_first', 'ship_company', -% 'ship_address1', 'ship_address2', 'ship_city', -% 'ship_county', 'ship_state', 'ship_zip', 'ship_country', -% 'ship_daytime','ship_night', 'ship_fax', -% -% 'geocode', -% -% 'select', #XXX key -% -% 'payauto', -% 'payinfo', 'payinfo1', 'payinfo2', 'paytype', -% 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', -% 'paystart_month', 'paystart_year', 'payissue', -% 'payip', -% 'paid', -% -% 'tax', -% 'invoicing_list', 'invoicing_list_POST', 'invoicing_list_FAX', -% 'invoice_terms', -% 'spool_cdr', -% 'squelch_cdr' -% ) { -% - - <INPUT TYPE="hidden" NAME="<% $hidden %>" VALUE=""> -% } -% -% my $ro_comments = $conf->exists('cust_main-use_comments')?'':'readonly'; -% if (!$ro_comments || $cust_main->comments) { - -<BR>Comments -<% &ntable("#cccccc") %> - <TR> - <TD> - <TEXTAREA COLS=80 ROWS=5 WRAP="HARD" NAME="comments" <%$ro_comments%>><% $cust_main->comments %></TEXTAREA> - </TD> - </TR> -</TABLE> -% -% } -% -%unless ( $custnum ) { -% # pry the wrong place for this logic. also pretty expensive -% #use FS::part_pkg; -% -% #false laziness, copied from FS::cust_pkg::order -% my $pkgpart; -% my $agentnum = ''; -% my @agents = $FS::CurrentUser::CurrentUser->agents; -% if ( scalar(@agents) == 1 ) { -% # $pkgpart->{PKGPART} is true iff $custnum may purchase PKGPART -% $pkgpart = $agents[0]->pkgpart_hashref; -% $agentnum = $agents[0]->agentnum; -% } else { -% #can't know (agent not chosen), so, allow all -% $agentnum = 'all'; -% my %typenum; -% foreach my $agent ( @agents ) { -% next if $typenum{$agent->typenum}++; -% $pkgpart->{$_}++ foreach keys %{ $agent->pkgpart_hashref } -% } -% } -% #eslaf -% -% my @part_pkg = grep { $_->svcpart('svc_acct') -% && ( $pkgpart->{ $_->pkgpart } -% || $agentnum eq 'all' -% || ( $agentnum ne 'all' -% && $agentnum -% && $_->agentnum -% && $_->agentnum == $agentnum -% ) -% ) -% } -% qsearch( 'part_pkg', { 'disabled' => '' }, '', 'ORDER BY pkg' ); # case? -% -% if ( @part_pkg ) { -% -% # print "<BR><BR>First package", &itable("#cccccc", "0 ALIGN=LEFT"), -% #apiabuse & undesirable wrapping -% -% - - <BR>First package - <% ntable("#cccccc") %> - - <TR> - <TD COLSPAN=2> - <% include('cust_main/select-domain.html', - 'pkgparts' => \@part_pkg, - 'saved_pkgpart' => $saved_pkgpart, - 'saved_domsvc' => $saved_domsvc, - ) - %> - </TD> - </TR> -% -% #false laziness: (mostly) copied from edit/svc_acct.cgi -% #$ulen = $svc_acct->dbdef_table->column('username')->length; -% my $ulen = dbdef->table('svc_acct')->column('username')->length; -% my $ulen2 = $ulen+2; -% my $passwordmax = $conf->config('passwordmax') || 8; -% my $pmax2 = $passwordmax + 2; -% - - - <TR> - <TD ALIGN="right">Username</TD> - <TD> - <INPUT TYPE="text" NAME="username" VALUE="<% $username %>" SIZE=<% $ulen2 %> MAXLENGTH=<% $ulen %>> - </TD> - </TR> - - <TR> - <TD ALIGN="right">Domain</TD> - <TD> - <SELECT NAME="domsvc"> - <OPTION>(none)</OPTION> - </SELECT> - </TD> - </TR> - - <TR> - <TD ALIGN="right">Password</TD> - <TD> - <INPUT TYPE="text" NAME="_password" VALUE="<% $password %>" SIZE=<% $pmax2 %> MAXLENGTH=<% $passwordmax %>> - (blank to generate) - </TD> - </TR> - - <TR> - <TD ALIGN="right">Access number</TD> - <TD><% FS::svc_acct_pop::popselector($popnum) %></TD> - </TR> - </TABLE> -% } +% 'payauto', +% 'payinfo', 'payinfo1', 'payinfo2', 'paytype', +% 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', +% 'paystart_month', 'paystart_year', 'payissue', +% 'payip', +% 'paid', +% ) { + <INPUT TYPE="hidden" NAME="<% $hidden %>" VALUE=""> % } +<% include('cust_main/bottomfixup.html') %> -<INPUT TYPE="hidden" NAME="otaker" VALUE="<% $cust_main->otaker %>"> -<BR> -<INPUT TYPE="button" NAME="submitButton" ID="submitButton" VALUE="<% $custnum ? "Apply Changes" : "Add Customer" %>" onClick="document.bottomform.submitButton.disabled=true; bottomfixup(this.form);"> <BR> +<INPUT TYPE = "button" + NAME = "submitButton" + ID = "submitButton" + VALUE = "<% $custnum ? "Apply Changes" : "Add Customer" %>" + onClick = "this.disabled=true; bottomfixup(this.form);" +> </FORM> <% include('/elements/footer.html') %> <%init> -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Edit customer'); - -#for misplaced logic below -#use FS::part_pkg; +my $curuser = $FS::CurrentUser::CurrentUser; -#for false laziness below (now more properly lazy) -#use FS::svc_acct_pop; - -#for (other) false laziness below -#use FS::agent; -#use FS::type_pkgs; +#probably redundant given the checks below... +die "access denied" + unless $curuser->access_right('New customer') + || $curuser->access_right('Edit customer'); my $conf = new FS::Conf; -my $taxpre = $conf->exists('tax-ship_address') ? 'ship_' : ''; #get record -my($custnum, $username, $password, $popnum, $cust_main, $saved_pkgpart, $saved_domsvc); -my(@invoicing_list); -my ($ss,$stateid,$payinfo); +my($custnum, $cust_main, $ss, $stateid, $payinfo, @invoicing_list); my $same = ''; +my $pkgpart_svcpart = ''; #first_pkg +my($username, $password, $popnum, $saved_domsvc) = ( '', '', 0, 0 ); #svc_acct +my %svc_phone = (); + if ( $cgi->param('error') ) { + $cust_main = new FS::cust_main ( { map { $_, scalar($cgi->param($_)) } fields('cust_main') } ); + $custnum = $cust_main->custnum; - $saved_domsvc = $cgi->param('domsvc') || ''; - if ( $saved_domsvc =~ /^(\d+)$/ ) { - $saved_domsvc = $1; - } else { - $saved_domsvc = ''; - } - $saved_pkgpart = $cgi->param('pkgpart_svcpart') || ''; - if ( $saved_pkgpart =~ /^(\d+)_/ ) { - $saved_pkgpart = $1; - } else { - $saved_pkgpart = ''; - } - $username = $cgi->param('username'); - $password = $cgi->param('_password'); - $popnum = $cgi->param('popnum'); + + die "access denied" + unless $curuser->access_right($custnum ? 'Edit customer' : 'New customer'); + @invoicing_list = split( /\s*,\s*/, $cgi->param('invoicing_list') ); $same = $cgi->param('same'); $cust_main->setfield('paid' => $cgi->param('paid')) if $cgi->param('paid'); $ss = $cust_main->ss; # don't mask an entered value on errors $stateid = $cust_main->stateid; # don't mask an entered value on errors $payinfo = $cust_main->payinfo; # don't mask an entered value on errors + + $pkgpart_svcpart = $cgi->param('pkgpart_svcpart') || ''; + + #svc_acct + $username = $cgi->param('username'); + $password = $cgi->param('_password'); + $popnum = $cgi->param('popnum'); + $saved_domsvc = $cgi->param('domsvc') || ''; + if ( $saved_domsvc =~ /^(\d+)$/ ) { + $saved_domsvc = $1; + } else { + $saved_domsvc = ''; + } + + #svc_phone + $svc_phone{$_} = $cgi->param($_) + foreach qw( countrycode phonenum sip_password pin phone_name ); + } elsif ( $cgi->keywords ) { #editing + + die "access denied" + unless $curuser->access_right('Edit customer'); + my( $query ) = $cgi->keywords; $query =~ /^(\d+)$/; $custnum=$1; @@ -741,31 +276,27 @@ if ( $cgi->param('error') ) { $paycvv =~ s/./*/g; $cust_main->paycvv($paycvv); } - $saved_pkgpart = 0; - $saved_domsvc = 0; - $username = ''; - $password = ''; - $popnum = 0; @invoicing_list = $cust_main->invoicing_list; $ss = $cust_main->masked('ss'); $stateid = $cust_main->masked('stateid'); $payinfo = $cust_main->paymask; -} else { + +} else { #new customer + + die "access denied" + unless $curuser->access_right('New customer'); + $custnum=''; $cust_main = new FS::cust_main ( {} ); $cust_main->otaker( &getotaker ); $cust_main->referral_custnum( $cgi->param('referral_custnum') ); - $saved_pkgpart = 0; - $saved_domsvc = 0; - $username = ''; - $password = ''; - $popnum = 0; @invoicing_list = (); push @invoicing_list, 'POST' unless $conf->exists('disablepostalinvoicedefault'); $ss = ''; $stateid = ''; $payinfo = ''; + } my $error = $cgi->param('error'); diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index 8724db9..ad83778 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -1,18 +1,15 @@ %if ( $payby_default eq 'HIDE' ) { % % $cust_main->payby('BILL') unless $cust_main->payby; +% my $payby = $cust_main->payby; - <INPUT TYPE="hidden" NAME="select" VALUE="<% $cust_main->payby %>"> - - </FORM> - - <FORM NAME="<% $cust_main->payby %>" STYLE="margin-top: 0; margin-bottom: 0"> + <INPUT TYPE="hidden" NAME="payby" VALUE="<% $payby %>"> - <INPUT TYPE="hidden" NAME="payinfo" VALUE="<% $cust_main->paymask %>"> + <INPUT TYPE="hidden" NAME="<%$payby%>_payinfo" VALUE="<% $cust_main->paymask %>"> % foreach my $field (qw( payname paycvv paystart_month paystart_year payissue payip paytype paystate )) { - <INPUT TYPE="hidden" NAME="<% $field %>" VALUE="<% $cust_main->getfield($field) %>"> + <INPUT TYPE="hidden" NAME="<% $payby.'_'.$field %>" VALUE="<% $cust_main->get($field) %>"> % } @@ -27,24 +24,18 @@ % die "unrecognized expiration date format: $date"; % } - <INPUT TYPE="hidden" NAME="exp_month" VALUE="<% $mon %>"> - <INPUT TYPE="hidden" NAME="exp_year" VALUE="<% $year %>"> - - </FORM> - - <FORM NAME="billing_bottomform" STYLE="margin-top: 0; margin-bottom: 0"> + <INPUT TYPE="hidden" NAME="<%$payby%>_exp_month" VALUE="<% $mon %>"> + <INPUT TYPE="hidden" NAME="<%$payby%>_exp_year" VALUE="<% $year %>"> <INPUT TYPE="hidden" NAME="tax" VALUE="<% $cust_main->tax %>"> <INPUT TYPE="hidden" NAME="invoicing_list" VALUE="<% join(', ', @invoicing_list) %>"> - </FORM> - % } else { % % my $r = qq!<font color="#ff0000">*</font> !; - <BR>Billing information + <BR><FONT SIZE="+1"><B>Billing information</B></FONT> <% &ntable("#cccccc") %> <TR> @@ -128,13 +119,13 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Card number </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $payinfo : '' ). qq!" MAXLENGTH=19 onChange="card_changed(this)" onKeyUp="card_changed(this)"></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="CARD_payinfo" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $payinfo : '' ). qq!" MAXLENGTH=19 onChange="card_changed(this)" onKeyUp="card_changed(this)"></TD></TR>!. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Expiration </TD>!. % '<TD WIDTH="408">'. % % include('/elements/select-month_year.html', -% 'prefix' => 'exp', +% 'prefix' => 'CARD_exp', % 'selected_date' => % ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->paydate : '' ), % ). @@ -145,14 +136,14 @@ % % qq!(<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/cvv2.html', 480, 352, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;">help</A>)!. % qq!</TD>!. -% '<TD WIDTH="408"><INPUT TYPE="text" NAME="paycvv" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ && !$cust_main->is_encrypted($cust_main->paycvv) ? $cust_main->paycvv : '' ). '" SIZE=4 MAXLENGTH=4>'. +% '<TD WIDTH="408"><INPUT TYPE="text" NAME="CARD_paycvv" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ && !$cust_main->is_encrypted($cust_main->paycvv) ? $cust_main->paycvv : '' ). '" SIZE=4 MAXLENGTH=4>'. % % % qq!<TR><TD ALIGN="right" WIDTH="200"><SPAN ID="paystart_label" $text_disabled>Start date </SPAN></TD>!. % '<TD WIDTH="408">'. % % include('/elements/select-month_year.html', -% 'prefix' => 'paystart', +% 'prefix' => 'CARD_paystart', % 'disabled' => $disabled, % 'empty_option' => 1, % 'start_year' => 2000, @@ -167,12 +158,12 @@ % ). % % qq!<SPAN ID="payissue_label" $text_disabled> or Issue number </SPAN>!. -% '<INPUT TYPE="text" NAME="payissue" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->payissue : '' ). qq!" SIZE=3 MAXLENGTH=2 $disabled></TD></TR>!. +% '<INPUT TYPE="text" NAME="CARD_payissue" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->payissue : '' ). qq!" SIZE=3 MAXLENGTH=2 $disabled></TD></TR>!. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Exact name on card </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payname" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->payname : '' ). qq!"></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="CARD_payname" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->payname : '' ). qq!"></TD></TR>!. % -% qq!<TR><TD COLSPAN=2 WIDTH="608"><INPUT TYPE="checkbox" NAME="payauto" !. ( $payby eq 'DCRD' ? '' : 'CHECKED' ). '> Charge future payments to this card automatically</TD></TR>'. +% qq!<TR><TD COLSPAN=2 WIDTH="608"><INPUT TYPE="checkbox" NAME="CARD_payauto" !. ( $payby eq 'DCRD' ? '' : 'CHECKED' ). '> Charge future payments to this card automatically</TD></TR>'. % % '</TABLE>', % @@ -181,21 +172,21 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Account number </TD>!. -% qq!<TD><INPUT TYPE="text" SIZE=12 NAME="payinfo1" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $account : '' ). '"></TD>'. -% qq!<TD ALIGN="right">Type</TD><TD><SELECT NAME="paytype">!. +% qq!<TD><INPUT TYPE="text" SIZE=12 NAME="CHEK_payinfo1" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $account : '' ). '"></TD>'. +% qq!<TD ALIGN="right">Type</TD><TD><SELECT NAME="CHEK_paytype">!. % join('', map { qq!<OPTION VALUE="$_" !.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>" } @FS::cust_main::paytypes). % qq!</SELECT></TD></TR>!. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}ABA/Routing number </TD>!. -% qq!<TD COLSPAN="3" WIDTH="408"><INPUT TYPE="text" SIZE=10 MAXLENGTH=9 NAME="payinfo2" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $aba : '' ). qq!" SIZE=10 MAXLENGTH=9> !. +% qq!<TD COLSPAN="3" WIDTH="408"><INPUT TYPE="text" SIZE=10 MAXLENGTH=9 NAME="CHEK_payinfo2" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $aba : '' ). qq!" SIZE=10 MAXLENGTH=9> !. % qq!(<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/ach.html', 380, 240, 'ach_popup' ), CAPTION, 'ACH Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;">help</A>)!. % qq!</TD></TR>!. % -% qq!<INPUT TYPE="hidden" NAME="exp_month" VALUE="12">!. -% qq!<INPUT TYPE="hidden" NAME="exp_year" VALUE="2037">!. +% qq!<INPUT TYPE="hidden" NAME="CHEK_exp_month" VALUE="12">!. +% qq!<INPUT TYPE="hidden" NAME="CHEK_exp_year" VALUE="2037">!. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Bank name </TD>!. -% qq!<TD COLSPAN="3" WIDTH="408"><INPUT TYPE="text" NAME="payname" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $cust_main->payname : '' ). qq!"></TD></TR>!. +% qq!<TD COLSPAN="3" WIDTH="408"><INPUT TYPE="text" NAME="CHEK_payname" VALUE="!. ( $payby =~ /^(CHEK|DCHK)$/ ? $cust_main->payname : '' ). qq!"></TD></TR>!. % ( $conf->exists('show_bankstate') ? % qq!<TR><TD ALIGN="right" WIDTH="200">$paystate_label</TD>!. % qq!<TD COLSPAN="3" WIDTH="408">!. @@ -203,14 +194,14 @@ % 'empty' => '(choose)', % 'state' => $cust_main->paystate, % 'country' => $cust_main->country, -% 'prefix' => 'pay', +% 'prefix' => 'CHEK_pay', % ). "</TD></TR>" -% : '<INPUT TYPE="hidden" NAME="paystate" VALUE="'. +% : '<INPUT TYPE="hidden" NAME="CHEK_paystate" VALUE="'. % $cust_main->paystate. '">' % ). % % -% qq!<TR><TD COLSPAN=4 WIDTH="608"><INPUT TYPE="checkbox" NAME="payauto" !. ( $payby eq 'DCHK' ? '' : 'CHECKED' ). '> Charge future payments to this electronic check automatically</TD></TR>'. +% qq!<TR><TD COLSPAN=4 WIDTH="608"><INPUT TYPE="checkbox" NAME="CHEK_payauto" !. ( $payby eq 'DCHK' ? '' : 'CHECKED' ). '> Charge future payments to this electronic check automatically</TD></TR>'. % % '<TR><TD> </TD></TR>'. % '<TR><TD> </TD></TR>'. @@ -223,11 +214,11 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Phone number </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby eq 'LECB' ? $cust_main->payinfo : '' ). qq!" MAXLENGTH=15 SIZE=16></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="LECB_payinfo" VALUE="!. ( $payby eq 'LECB' ? $cust_main->payinfo : '' ). qq!" MAXLENGTH=15 SIZE=16></TD></TR>!. % -% qq!<INPUT TYPE="hidden" NAME="exp_month" VALUE="12">!. -% qq!<INPUT TYPE="hidden" NAME="exp_year" VALUE="2037">!. -% qq!<INPUT TYPE="hidden" NAME="payname" VALUE="">!. +% qq!<INPUT TYPE="hidden" NAME="LECB_exp_month" VALUE="12">!. +% qq!<INPUT TYPE="hidden" NAME="LECB_exp_year" VALUE="2037">!. +% qq!<INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!. % % '<TR><TD> </TD></TR>'. % '<TR><TD> </TD></TR>'. @@ -243,13 +234,13 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">P.O. </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby eq 'BILL' ? $cust_main->payinfo : '' ). qq!"></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="BILL_payinfo" VALUE="!. ( $payby eq 'BILL' ? $cust_main->payinfo : '' ). qq!"></TD></TR>!. % -% qq!<INPUT TYPE="hidden" NAME="exp_month" VALUE="12">!. -% qq!<INPUT TYPE="hidden" NAME="exp_year" VALUE="2037">!. +% qq!<INPUT TYPE="hidden" NAME="BILL_exp_month" VALUE="12">!. +% qq!<INPUT TYPE="hidden" NAME="BILL_exp_year" VALUE="2037">!. % % qq!<TR><TD ALIGN="right" WIDTH="200">Attention </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payname" VALUE="!. ( $payby eq 'BILL' ? $cust_main->payname : '' ). qq!"></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="BILL_payname" VALUE="!. ( $payby eq 'BILL' ? $cust_main->payname : '' ). qq!"></TD></TR>!. % % '<TR><TD> </TD></TR>'. % '<TR><TD> </TD></TR>'. @@ -264,13 +255,13 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Approved by </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE=""></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""></TD></TR>!. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Expiration </TD>!. % '<TD WIDTH="408">'. % % include('/elements/select-month_year.html', -% 'prefix' => 'exp', +% 'prefix' => 'COMP_exp', % 'selected_date' => % ( $payby eq 'COMP' ? $cust_main->paydate : '' ), % ). @@ -290,7 +281,7 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Amount </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="paid" VALUE="!. ( $payby eq 'CASH' ? $cust_main->paid : '' ). qq!"></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="CASH_paid" VALUE="!. ( $payby eq 'CASH' ? $cust_main->paid : '' ). qq!"></TD></TR>!. % % '<TR><TD> </TD></TR>'. % '<TR><TD> </TD></TR>'. @@ -306,7 +297,7 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Amount </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="paid" VALUE="!. ( $payby eq 'WEST' ? $cust_main->paid : '' ). qq!"></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="WEST_paid" VALUE="!. ( $payby eq 'WEST' ? $cust_main->paid : '' ). qq!"></TD></TR>!. % % '<TR><TD> </TD></TR>'. % '<TR><TD> </TD></TR>'. @@ -322,7 +313,7 @@ % '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'. % % qq!<TR><TD ALIGN="right" WIDTH="200">${r}Amount </TD>!. -% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="paid" VALUE="!. ( $payby eq 'MCRD' ? $cust_main->paid : '' ). qq!"></TD></TR>!. +% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="MCRD_paid" VALUE="!. ( $payby eq 'MCRD' ? $cust_main->paid : '' ). qq!"></TD></TR>!. % % '<TR><TD> </TD></TR>'. % '<TR><TD> </TD></TR>'. @@ -336,57 +327,51 @@ % ); % % #this should use FS::payby -% my %allopt = ( -% 'CARD' => 'Credit card', -% 'CHEK' => 'Electronic check', -% 'LECB' => 'Phone bill billing', -% 'BILL' => 'Billing', -% 'CASH' => 'Cash', # initial payment, then billing', -% 'WEST' => 'Western Union', # initial payment, then billing', -% 'MCRD' => 'Manual credit card', # initial payment, then billing', -% 'COMP' => 'Complimentary', -% ); -% if ( $cust_main->custnum ) { #don't offer CASH/WEST/MCRD initial payment types -% # when editing customer +% my @allopt = qw( CARD CHEK LECB BILL CASH WEST MCRD COMP ); +% +% my %allopt = map { $_ => FS::payby->shortname($_) } @allopt; +% +% if ( $cust_main->custnum ) { +% #don't offer CASH/WEST/MCRD initial payment types when editing customer % delete $allopt{$_} for qw(CASH WEST MCRD); % } % -% tie my %options, 'Tie::IxHash', -% map { $_ => $allopt{$_} } -% grep { exists $allopt{$_} } -% @payby; +% my @options = grep exists( $allopt{$_} ), @payby; % % my %payby2option = ( -% ( map { $_ => $_ } keys %options ), +% ( map { $_ => $_ } @options ), % 'DCRD' => 'CARD', % 'DCHK' => 'CHEK', % ); -% -% my $widget = new HTML::Widgets::SelectLayers( -% 'options' => \%options, -% #'form_name' => 'dummy', -% #'form_action' => 'nothingyet', -% #chops bottom of page in IE# 'under_position' => 'absolute', -% 'html_between' => '</TD></TR></TABLE>', -% 'selected_layer' => $payby2option{$payby || $payby_default || $payby[0] }, -% 'layer_callback' => sub { my $layer = shift; $payby{$layer}; }, -% ); -% -% - - - <TD WIDTH="408"><% $widget->html %> - <FORM NAME="billing_bottomform" STYLE="margin-top: 0; margin-bottom: 0"> + <TD WIDTH="408"> + <% include( '/elements/selectlayers.html', + 'field' => 'payby', + 'curr_value' => $payby2option{$payby || $payby_default || $payby[0] }, + 'options' => \@options, + 'labels' => \%allopt, + 'html_between' => '</TD></TR></TABLE>', + 'layer_callback' => sub { my $layer = shift; $payby{$layer}; }, + ) + %> <% &ntable("#cccccc") %> <TR><TD> </TD></TR> +% my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); + <TR> - <TD WIDTH="608" COLSPAN="2"><INPUT TYPE="checkbox" NAME="tax" VALUE="Y" <% $cust_main->tax eq "Y" ? 'CHECKED' : '' %>> Tax Exempt</TD> + <TD WIDTH="608" COLSPAN="2"><INPUT TYPE="checkbox" NAME="tax" VALUE="Y" <% $cust_main->tax eq "Y" ? 'CHECKED' : '' %>> Tax Exempt<% @exempt_groups ? ' (all taxes)' : '' %></TD> </TR> +% foreach my $exempt_group ( @exempt_groups ) { +% #escape $exempt_group for NAME + <TR> + <TD WIDTH="608" COLSPAN="2"> <INPUT TYPE="checkbox" NAME="tax_<% $exempt_group %>" VALUE="Y" <% $cust_main->tax_exemption($exempt_group) ? 'CHECKED' : '' %>> Tax Exempt (<% $exempt_group %> taxes)<TD> + </TR> +% } + % unless ( $conf->exists('emailinvoiceonly') ) { <TR> @@ -426,14 +411,10 @@ <TR> <TD ALIGN="right" WIDTH="200">Invoice terms </TD> <TD WIDTH="408"> - <SELECT NAME="invoice_terms"> - <OPTION VALUE="">Default (<% $conf->config('invoice_default_terms') || 'Payable upon receipt' %>) -% foreach my $term ( 'Payable upon receipt', -% ( map "Net $_", 0, 10, 15, 30, 45, 60 ), -% ) { - <OPTION VALUE="<% $term %>" <% $cust_main->invoice_terms eq $term ? ' SELECTED' : '' %>><% $term %> -% } - </SELECT> + <% include('/elements/select-terms.html', + 'curr_value' => $cust_main->invoice_terms, + ) + %> </TD> </TR> @@ -442,22 +423,40 @@ <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="spool_cdr" VALUE="Y" <% $cust_main->spool_cdr eq "Y" ? 'CHECKED' : '' %>> Spool CDRs</TD> </TR> % } else { - <INPUT TYPE="hidden" NAME="spool_cdr" VALUE="<% $cust_main->spool_cdr %>"> -% } +% } % if ( $conf->exists('voip-cust_cdr_squelch') ) { <TR> <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="squelch_cdr" VALUE="Y" <% $cust_main->squelch_cdr eq "Y" ? 'CHECKED' : '' %>> Omit CDRs from invoices</TD> </TR> % } else { - <INPUT TYPE="hidden" NAME="squelch_cdr" VALUE="<% $cust_main->squelch_cdr %>"> -% } +% } - </TABLE> +% if ( $conf->exists('voip-cust_email_csv_cdr') ) { + <TR> + <TD COLSPAN="2"><INPUT TYPE="checkbox" NAME="email_csv_cdr" VALUE="Y" <% $cust_main->email_csv_cdr eq "Y" ? 'CHECKED' : '' %>> Attach CDRs as CSV to emailed invoices</TD> + </TR> +% } else { + <INPUT TYPE="hidden" NAME="email_csv_cdr" VALUE="<% $cust_main->email_csv_cdr %>"> +% } - </FORM> +% if ( $show_term || $cust_main->cdr_termination_percentage ) { + <TR> + <TD ALIGN="right">CDR termination settlement</TD> + <TD><INPUT TYPE = "text" + NAME = "cdr_termination_percentage" + SIZE = 6 + VALUE = "<% $cust_main->cdr_termination_percentage %>" + STYLE = "text-align:right;" + ><B>%</B></TD> + </TR> +% } else { + <INPUT TYPE="hidden" NAME="cdr_termination_percentage" VALUE="<% $cust_main->cdr_termination_percentage %>"> +% } + + </TABLE> <% $r %> required fields % } @@ -481,4 +480,13 @@ my @payby = grep /\w/, $conf->config('payby'); @payby = (qw( CARD DCRD CHEK DCHK LECB BILL CASH COMP )) unless @payby; +my $show_term = ''; +if ( $cust_main->custnum ) { + #false laziness w/view/cust_main/billing.html + my $term_sql = "SELECT COUNT(*) FROM cust_pkg LEFT JOIN part_pkg USING ( pkgpart ) WHERE custnum = ? AND plan = 'cdr_termination' LIMIT 1"; + my $term_sth = dbh->prepare($term_sql) or die dbh->errstr; + $term_sth->execute($cust_main->custnum) or die $term_sth->errstr; + $show_term = $term_sth->fetchrow_arrayref->[0]; +} + </%init> diff --git a/httemplate/edit/cust_main/birthdate.html b/httemplate/edit/cust_main/birthdate.html new file mode 100644 index 0000000..415aba3 --- /dev/null +++ b/httemplate/edit/cust_main/birthdate.html @@ -0,0 +1,15 @@ +<% ntable("#cccccc", 2) %> + <% include ('/elements/tr-input-date-field.html', + 'birthdate', + $cust_main->birthdate, + 'Date of Birth', + $conf->config('date_format') || "%m/%d/%Y", + 1) + %> +</TABLE> +<%init> + +my( $cust_main, %opt ) = @_; +my $conf = new FS::Conf; + +</%init> diff --git a/httemplate/edit/cust_main/bottomfixup.html b/httemplate/edit/cust_main/bottomfixup.html new file mode 100644 index 0000000..1b29c67 --- /dev/null +++ b/httemplate/edit/cust_main/bottomfixup.html @@ -0,0 +1,19 @@ +<% include('/elements/init_overlib.html') %> + +<% include( '/elements/xmlhttp.html', + 'url' => $p.'misc/xmlhttp-cust_main-address_standardize.html', + 'subs' => [ 'address_standardize' ], + #'method' => 'POST', #could get too long? + ) +%> + +<% include( '/elements/xmlhttp.html', + 'url' => $p.'misc/xmlhttp-cust_main-censustract.html', + 'subs' => [ 'censustract' ], + #'method' => 'POST', #could get too long? + ) +%> + +<SCRIPT TYPE="text/javascript"> + <% include('bottomfixup.js') %> +</SCRIPT> diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js new file mode 100644 index 0000000..1a06d94 --- /dev/null +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -0,0 +1,398 @@ +function bottomfixup(what) { + +%# ../cust_main.cgi + var layervars = new Array( + 'payauto', + 'payinfo', 'payinfo1', 'payinfo2', 'paytype', + 'payname', 'paystate', 'exp_month', 'exp_year', 'paycvv', + 'paystart_month', 'paystart_year', 'payissue', + 'payip', + 'paid' + ); + + var cf = document.CustomerForm; + var payby = cf.payby.options[cf.payby.selectedIndex].value; + for ( f=0; f < layervars.length; f++ ) { + var field = layervars[f]; + copyelement( cf.elements[payby + '_' + field], + cf.elements[field] + ); + } + + //this part does USPS address correction + + // XXX should this be first and should we update the form fields that are + // displayed??? + + var cf = document.CustomerForm; + + var state_el = cf.elements['state']; + var ship_state_el = cf.elements['ship_state']; + + //address_standardize( + var cust_main = new Array( + 'company', cf.elements['company'].value, + 'address1', cf.elements['address1'].value, + 'address2', cf.elements['address2'].value, + 'city', cf.elements['city'].value, + 'state', state_el.options[ state_el.selectedIndex ].value, + 'zip', cf.elements['zip'].value, + + 'ship_company', cf.elements['ship_company'].value, + 'ship_address1', cf.elements['ship_address1'].value, + 'ship_address2', cf.elements['ship_address2'].value, + 'ship_city', cf.elements['ship_city'].value, + 'ship_state', ship_state_el.options[ ship_state_el.selectedIndex ].value, + 'ship_zip', cf.elements['ship_zip'].value + ); + + address_standardize( cust_main, update_address ); + +} + +var standardize_address; + +function update_address(arg) { + + var argsHash = eval('(' + arg + ')'); + + var changed = argsHash['address_standardized']; + var ship_changed = argsHash['ship_address_standardized']; + var error = argsHash['error']; + var ship_error = argsHash['ship_error']; + + + //yay closures + standardize_address = function () { + + var cf = document.CustomerForm; + var state_el = cf.elements['state']; + var ship_state_el = cf.elements['ship_state']; + + if ( changed ) { + cf.elements['company'].value = argsHash['new_company']; + cf.elements['address1'].value = argsHash['new_address1']; + cf.elements['address2'].value = argsHash['new_address2']; + cf.elements['city'].value = argsHash['new_city']; + setselect(cf.elements['state'], argsHash['new_state']); + cf.elements['zip'].value = argsHash['new_zip']; + } + + if ( ship_changed ) { + cf.elements['ship_company'].value = argsHash['new_ship_company']; + cf.elements['ship_address1'].value = argsHash['new_ship_address1']; + cf.elements['ship_address2'].value = argsHash['new_ship_address2']; + cf.elements['ship_city'].value = argsHash['new_ship_city']; + setselect(cf.elements['ship_state'], argsHash['new_ship_state']); + cf.elements['ship_zip'].value = argsHash['new_ship_zip']; + } + + post_standardization(); + + } + + + + if ( changed || ship_changed ) { + +% if ( $conf->exists('cust_main-auto_standardize_address') ) { + + standardize_address(); + +% } else { + + // popup a confirmation popup + + var confirm_change = + '<CENTER><BR><B>Confirm address standardization</B><BR><BR>' + + '<TABLE>'; + + if ( changed ) { + + confirm_change = confirm_change + + '<TR><TH>Entered billing address</TH>' + + '<TH>Standardized billing address</TH></TR>'; + // + '<TR><TD> </TD><TD> </TD></TR>'; + + if ( argsHash['company'] || argsHash['new_company'] ) { + confirm_change = confirm_change + + '<TR><TD>' + argsHash['company'] + + '</TD><TD>' + argsHash['new_company'] + '</TD></TR>'; + } + + confirm_change = confirm_change + + '<TR><TD>' + argsHash['address1'] + + '</TD><TD>' + argsHash['new_address1'] + '</TD></TR>' + + '<TR><TD>' + argsHash['address2'] + + '</TD><TD>' + argsHash['new_address2'] + '</TD></TR>' + + '<TR><TD>' + argsHash['city'] + ', ' + argsHash['state'] + ' ' + argsHash['zip'] + + '</TD><TD>' + argsHash['new_city'] + ', ' + argsHash['new_state'] + ' ' + argsHash['new_zip'] + '</TD></TR>' + + '<TR><TD> </TD><TD> </TD></TR>'; + + } + + if ( ship_changed ) { + + confirm_change = confirm_change + + '<TR><TH>Entered service address</TH>' + + '<TH>Standardized service address</TH></TR>'; + // + '<TR><TD> </TD><TD> </TD></TR>'; + + if ( argsHash['ship_company'] || argsHash['new_ship_company'] ) { + confirm_change = confirm_change + + '<TR><TD>' + argsHash['ship_company'] + + '</TD><TD>' + argsHash['new_ship_company'] + '</TD></TR>'; + } + + confirm_change = confirm_change + + '<TR><TD>' + argsHash['ship_address1'] + + '</TD><TD>' + argsHash['new_ship_address1'] + '</TD></TR>' + + '<TR><TD>' + argsHash['ship_address2'] + + '</TD><TD>' + argsHash['new_ship_address2'] + '</TD></TR>' + + '<TR><TD>' + argsHash['ship_city'] + ', ' + argsHash['ship_state'] + ' ' + argsHash['ship_zip'] + + '</TD><TD>' + argsHash['new_ship_city'] + ', ' + argsHash['new_ship_state'] + ' ' + argsHash['new_ship_zip'] + '</TD></TR>' + + '<TR><TD> </TD><TD> </TD></TR>'; + + } + + var addresses = 'address'; + var height = 268; + if ( changed && ship_changed ) { + addresses = 'addresses'; + height = 396; // #what + } + + confirm_change = confirm_change + + '<TR><TD>' + + '<BUTTON TYPE="button" onClick="post_standardization();"><IMG SRC="<%$p%>images/error.png" ALT=""> Use entered ' + addresses + '</BUTTON>' + + '</TD><TD>' + + '<BUTTON TYPE="button" onClick="standardize_address();"><IMG SRC="<%$p%>images/tick.png" ALT=""> Use standardized ' + addresses + '</BUTTON>' + + '</TD></TR>' + + '<TR><TD COLSPAN=2 ALIGN="center">' + + '<BUTTON TYPE="button" onClick="document.CustomerForm.submitButton.disabled=false; parent.cClick();"><IMG SRC="<%$p%>images/cross.png" ALT=""> Cancel submission</BUTTON></TD></TR>' + + + '</TABLE></CENTER>'; + + overlib( confirm_change, CAPTION, 'Confirm address standardization', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, height, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + +% } + + } else { + + post_standardization(); + + } + + +} + +function post_standardization() { + + var cf = document.CustomerForm; + +% if ( $conf->exists('enable_taxproducts') ) { + + if ( new String(cf.elements['<% $taxpre %>zip'].value).length < 10 ) + { + + var country_el = cf.elements['<% $taxpre %>country']; + var country = country_el.options[ country_el.selectedIndex ].value; + var geocode = cf.elements['geocode'].value; + + if ( country == 'CA' || country == 'US' ) { + + var state_el = cf.elements['<% $taxpre %>state']; + var state = state_el.options[ state_el.selectedIndex ].value; + + var url = "cust_main/choose_tax_location.html" + + "?data_vendor=cch-zip" + + ";city=" + cf.elements['<% $taxpre %>city'].value + + ";state=" + state + + ";zip=" + cf.elements['<% $taxpre %>zip'].value + + ";country=" + country + + ";geocode=" + geocode + + ";"; + + // popup a chooser + OLgetAJAX( url, update_geocode, 300 ); + + } else { + + cf.elements['geocode'].value = 'DEFAULT'; + post_geocode(); + + } + + } else { + + post_geocode(); + + } + +% } else { + + post_geocode(); + +% } + +} + +function post_geocode() { + +% if ( $conf->exists('cust_main-require_censustract') ) { + + //alert('fetch census tract data'); + var cf = document.CustomerForm; + var state_el = cf.elements['ship_state']; + var census_data = new Array( + 'year', <% $conf->config('census_year') || '2009' %>, + 'address', cf.elements['ship_address1'].value, + 'city', cf.elements['ship_city'].value, + 'state', state_el.options[ state_el.selectedIndex ].value, + 'zip', cf.elements['ship_zip'].value + ); + + censustract( census_data, update_censustract ); + +% }else{ + + document.CustomerForm.submit(); + +% } + +} + +function update_geocode() { + + //yay closures + set_geocode = function (what) { + + var cf = document.CustomerForm; + + //alert(what.options[what.selectedIndex].value); + var argsHash = eval('(' + what.options[what.selectedIndex].value + ')'); + cf.elements['<% $taxpre %>city'].value = argsHash['city']; + setselect(cf.elements['<% $taxpre %>state'], argsHash['state']); + cf.elements['<% $taxpre %>zip'].value = argsHash['zip']; + cf.elements['geocode'].value = argsHash['geocode']; + post_geocode(); + + } + + // popup a chooser + + overlib( OLresponseAJAX, CAPTION, 'Select tax location', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + +} + +var set_censustract; + +function update_censustract(arg) { + + var argsHash = eval('(' + arg + ')'); + + var cf = document.CustomerForm; + + var msacode = argsHash['msacode']; + var statecode = argsHash['statecode']; + var countycode = argsHash['countycode']; + var tractcode = argsHash['tractcode']; + var error = argsHash['error']; + + var newcensus = + new String(statecode) + + new String(countycode) + + new String(tractcode).replace(/\s$/, ''); // JSON 1 workaround + + set_censustract = function () { + + cf.elements['censustract'].value = newcensus + cf.submit(); + + } + + if (error || cf.elements['censustract'].value != newcensus) { + // popup an entry dialog + + if (error) { newcensus = error; } + newcensus.replace(/.*ndefined.*/, 'Not found'); + + var choose_censustract = + '<CENTER><BR><B>Confirm censustract</B><BR>' + + '<A href="http://maps.ffiec.gov/FFIECMapper/TGMapSrv.aspx?' + + 'census_year=<% $conf->config('census_year') || '2008' %>' + + '&latitude=' + cf.elements['latitude'].value + + '&longitude=' + cf.elements['longitude'].value + + '" target="_blank">Map service module location</A><BR>' + + '<A href="http://maps.ffiec.gov/FFIECMapper/TGMapSrv.aspx?' + + 'census_year=<% $conf->config('census_year') || '2008' %>' + + '&zip_code=' + cf.elements['ship_zip'].value + + '" target="_blank">Map zip code center</A><BR><BR>' + + '<TABLE>'; + + choose_censustract = choose_censustract + + '<TR><TH style="width:50%">Entered census tract</TH>' + + '<TH style="width:50%">Calculated census tract</TH></TR>' + + '<TR><TD>' + cf.elements['censustract'].value + + '</TD><TD>' + newcensus + '</TD></TR>' + + '<TR><TD> </TD><TD> </TD></TR>'; + + choose_censustract = choose_censustract + + '<TR><TD ALIGN="center">' + + '<BUTTON TYPE="button" onClick="document.CustomerForm.submit();"><IMG SRC="<%$p%>images/error.png" ALT=""> Use entered census tract </BUTTON>' + + '</TD><TD ALIGN="center">' + + '<BUTTON TYPE="button" onClick="set_censustract();"><IMG SRC="<%$p%>images/tick.png" ALT=""> Use calculated census tract </BUTTON>' + + '</TD></TR>' + + '<TR><TD COLSPAN=2 ALIGN="center">' + + '<BUTTON TYPE="button" onClick="document.CustomerForm.submitButton.disabled=false; parent.cClick();"><IMG SRC="<%$p%>images/cross.png" ALT=""> Cancel submission</BUTTON></TD></TR>' + + + '</TABLE></CENTER>'; + + overlib( choose_censustract, CAPTION, 'Confirm censustract', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', TEXTSIZE, 3 ); + + } else { + + cf.submit(); + + } + +} + +function copyelement(from, to) { + if ( from == undefined ) { + to.value = ''; + } else if ( from.type == 'select-one' ) { + to.value = from.options[from.selectedIndex].value; + //alert(from + " (" + from.type + "): " + to.name + " => (" + from.selectedIndex + ") " + to.value); + } else if ( from.type == 'checkbox' ) { + if ( from.checked ) { + to.value = from.value; + } else { + to.value = ''; + } + } else { + if ( from.value == undefined ) { + to.value = ''; + } else { + to.value = from.value; + } + } + //alert(from + " (" + from.type + "): " + to.name + " => " + to.value); +} + +function setselect(el, value) { + + for ( var s = 0; s < el.options.length; s++ ) { + if ( el.options[s].value == value ) { + el.selectedIndex = s; + } + } + +} +<%init> + +my $conf = new FS::Conf; + +my $taxpre = $conf->exists('tax-ship_address') ? 'ship_' : ''; + +</%init> diff --git a/httemplate/edit/cust_main/choose_tax_location.html b/httemplate/edit/cust_main/choose_tax_location.html index bd8b95c..ac475c5 100644 --- a/httemplate/edit/cust_main/choose_tax_location.html +++ b/httemplate/edit/cust_main/choose_tax_location.html @@ -1,5 +1,6 @@ <FORM NAME="choosegeocodeform"> <CENTER><BR><B>Choose tax location</B><BR><BR> +<P>the geocode is:<% $header %></P> <P STYLE="<% $style %>"><% $header %></P> <SELECT NAME='geocodes' ID='geocodes' STYLE="<% $style %>"> @@ -18,7 +19,7 @@ % foreach qw( city county state ); % $content .= $location->cityflag eq 'I' ? 'Y' : 'N' ; % my $selected = '' ; -% if (!$have_selected && lc($location->city) eq lc($location{city})) { +% if ($geocode && $location->geocode eq $geocode) { % $selected = 'SELECTED'; % } <OPTION VALUE="<% $value %>" STYLE="<% $style %>" <% $selected %>><% $content %> @@ -26,8 +27,8 @@ </SELECT><BR><BR> <TABLE><TR> - <TD> <BUTTON TYPE="button" onClick="set_geocode(document.getElementById('geocodes')); document.bottomform.submit();"><IMG SRC="<%$p%>images/tick.png" ALT=""> Set location </BUTTON></TD> - <TD><BUTTON TYPE="button" onClick="document.bottomform.submitButton.disabled=false; parent.cClick();"><IMG SRC="<%$p%>images/cross.png" ALT=""> Cancel submission </BUTTON></TD> + <TD> <BUTTON TYPE="button" onClick="set_geocode(document.getElementById('geocodes'));"><IMG SRC="<%$p%>images/tick.png" ALT=""> Set location </BUTTON></TD> + <TD><BUTTON TYPE="button" onClick="document.CustomerForm.submitButton.disabled=false; parent.cClick();"><IMG SRC="<%$p%>images/cross.png" ALT=""> Cancel submission </BUTTON></TD> </TR> </TABLE> @@ -36,7 +37,6 @@ <%init> my $conf = new FS::Conf; -my $have_selected = 0; my %location = (); @@ -46,6 +46,8 @@ my %location = (); ($location{zip}) = $cgi->param('zip') =~ /^([-\w ]+)$/; ($location{country}) = $cgi->param('country') =~ /^([\w ]+)$/; +my($geocode) = $cgi->param('geocode') =~ /^([\w]+)$/; + my($zip5, $zip4) = split('-', $location{zip}); #only support US & CA diff --git a/httemplate/edit/cust_main/contact.html b/httemplate/edit/cust_main/contact.html index 27dd385..3ccee62 100644 --- a/httemplate/edit/cust_main/contact.html +++ b/httemplate/edit/cust_main/contact.html @@ -32,6 +32,7 @@ 'disabled' => $disabled, 'same_checked' => $opt{'same_checked'}, 'geocode' => $opt{'geocode'}, + 'censustract' => $opt{'censustract'}, ) %> @@ -110,6 +111,12 @@ $cust_main->set($pre.'state', $statedefault ) $cust_main->set('stateid_state', $cust_main->state ) unless $pre || $cust_main->get('stateid_state'); +$opt{geocode} ||= $cust_main->get('geocode'); + +if ( $conf->exists('cust_main-require_censustract') ) { + $opt{censustract} ||= $cust_main->censustract; +} + #my($county_html, $state_html, $country_html) = # FS::cust_main_county::regionselector( $cust_main->get($pre.'county'), # $cust_main->get($pre.'state'), diff --git a/httemplate/edit/cust_main/first_pkg.html b/httemplate/edit/cust_main/first_pkg.html new file mode 100644 index 0000000..0de33c0 --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg.html @@ -0,0 +1,55 @@ +% if ( @part_pkg ) { + + <BR><BR> + <FONT SIZE="+1"><B>First package</B></FONT> + <% ntable("#cccccc") %> + + <TR> + <TD COLSPAN=2> + <% include('first_pkg/select-part_pkg.html', + 'part_pkg' => \@part_pkg, + %opt, + # map { $_ => $opt{$_} } qw( pkgpart_svcpart saved_domsvc ) + ) + %> + +% } +<%init> + +my( $cust_main, %opt ) = @_; + +# pry the wrong place for this logic. also pretty expensive + +#false laziness, copied from FS::cust_pkg::order +my $pkgpart; +my $agentnum = ''; +my @agents = $FS::CurrentUser::CurrentUser->agents; +if ( scalar(@agents) == 1 ) { + # $pkgpart->{PKGPART} is true iff $custnum may purchase PKGPART + $pkgpart = $agents[0]->pkgpart_hashref; + $agentnum = $agents[0]->agentnum; +} else { + #can't know (agent not chosen), so, allow all + $agentnum = 'all'; + my %typenum; + foreach my $agent ( @agents ) { + next if $typenum{$agent->typenum}++; + $pkgpart->{$_}++ foreach keys %{ $agent->pkgpart_hashref } + } +} +#eslaf + +my @first_svc = ( 'svc_acct', 'svc_phone' ); + +my @part_pkg = + grep { $_->svcpart(\@first_svc) + && ( $pkgpart->{ $_->pkgpart } + || $agentnum eq 'all' + || ( $agentnum ne 'all' && $agentnum && $_->agentnum + && $_->agentnum == $agentnum + ) + ) + } + qsearch( 'part_pkg', { 'disabled' => '' }, '', 'ORDER BY pkg' ); # case? + +</%init> diff --git a/httemplate/edit/cust_main/first_pkg/select-part_pkg.html b/httemplate/edit/cust_main/first_pkg/select-part_pkg.html new file mode 100644 index 0000000..871e1cd --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg/select-part_pkg.html @@ -0,0 +1,170 @@ +<% include('/elements/xmlhttp.html', + 'url' => $url_prefix.'misc/svc_acct-domains.cgi', + 'subs' => [ $opt{'prefix'}. 'get_domains' ], + ) +%> + +<% include('/elements/xmlhttp.html', + 'url' => $url_prefix.'misc/part_svc-columns.cgi', + 'subs' => [ $opt{'prefix'}. 'get_part_svc' ], + ) +%> + +<INPUT TYPE="hidden" NAME="svcdb" VALUE=""> + +<SCRIPT TYPE="text/javascript"> + + function selopt(what,value,text,selected) { + var optionName = new Option(text, value, false, selected); + var length = what.length; + what.options[length] = optionName; + } + + var pkgpart_svcpart2svcdb = { +% foreach my $pkgpart ( map $_->pkgpart, @part_pkg ) { + "<% $pkgpart_svcpart{$pkgpart} %>":"<% $svcdb{$pkgpart} %>", +% } + '':'' + }; + + function <% $opt{'prefix'} %>pkgpart_svcpart_changed_too(what,selected) { + + <% $opt{'onchange'} %>; + + pkgpart_svcpart = what.options[what.selectedIndex].value; + + var svcdb = pkgpart_svcpart2svcdb[pkgpart_svcpart]; + + what.form.svcdb.value = svcdb; + + if ( svcdb == 'svc_acct' ) { + + // go get the new domains + function <% $opt{'prefix'} %>update_domains(domains) { + + // blank the current domain list + for ( var i = what.form.<% $opt{'prefix'} %>domsvc.length; i >= 0; i-- ) + what.form.<% $opt{'prefix'} %>domsvc.options[i] = null; + + // add the new domains + var domainArray = eval('(' + domains + ')' ); + for ( var s = 0; s < domainArray.length; s=s+2 ) { + var domainLabel = domainArray[s+1]; + if ( domainLabel == "" ) + domainLabel = '(n/a)'; + selopt( what.form.<% $opt{'prefix'} %>domsvc, + domainArray[s], + domainLabel, + (domainArray[s] == selected) ? true : false + ); + } + + } + + <% $opt{'prefix'} %>get_domains( pkgpart_svcpart, + <% $opt{'prefix'} %>update_domains + ); + + } else if ( svcdb == 'svc_phone' ) { + + function <% $opt{'prefix'} %>update_svc_phone(part_svc_column) { + var colArray = eval('(' + part_svc_column + ')' ); + for ( var s = 0; s < colArray.length; s=s+3 ) { + var name = colArray[s]; + var flag = colArray[s+1]; + var value = colArray[s+2]; + var td_label = document.getElementById(name+'_label_td'); + var td = document.getElementById(name+'_td'); + var input = document.getElementById(name); + if ( flag == 'D' ) { + if ( ! input.value ) { input.value = value; } + td_label.style.display = '' + td.style.display = '' + } else if ( flag == 'F' ) { + input.value = value; + td_label.style.display = 'none' + td.style.display = 'none' + } else { + td_label.style.display = '' + td.style.display = '' + } + } + } + + <% $opt{'prefix'} %>get_part_svc( pkgpart_svcpart, + <% $opt{'prefix'} %>update_svc_phone + ); + + } + + } + +</SCRIPT> + +<% include( '/elements/selectlayers.html', + 'field' => $opt{'prefix'}. 'pkgpart_svcpart', + 'curr_value' => $opt{pkgpart_svcpart}, + 'options' => \@options, + 'labels' => \%labels, + 'html_between' => '</TD></TR></TABLE>', + #'onchange' => $opt{'prefix'}. 'pkgpart_svcpart_changed(this,0);', + 'onchange' => $opt{'prefix'}. 'pkgpart_svcpart_changed_too(what,0)', + + 'layer_callback' => $layer_callback, + 'layermap' => \%layermap, + ) +%> + +<SCRIPT TYPE="text/javascript"> + pkgpart_svcpart_changed_too( document.CustomerForm.pkgpart_svcpart, + <% $opt{saved_domsvc} %> + ); +</SCRIPT> + +<%init> + +my %opt = @_; + +foreach my $opt (qw( svc_part pkgparts saved_pkgpart saved_domsvc prefix)) { + $opt{$_} = '' unless exists($opt{$_}) && defined($opt{$_}); +} +$opt{saved_domsvc} = 0 unless $opt{saved_domsvc}; + +my $url_prefix = $opt{'relurls'} ? '' : $p; + +my @part_pkg = @{$opt{'part_pkg'}}; + +my @first_svc = ( 'svc_acct', 'svc_phone' ); + +my %pkgpart_svcpart = (); +my %svcdb = (); +my %layermap = (); +foreach my $part_pkg ( @part_pkg ) { + my $pkgpart = $part_pkg->pkgpart; + my $pkgpart_svcpart = $pkgpart. "_". $part_pkg->svcpart(\@first_svc); + $pkgpart_svcpart{$pkgpart} = $pkgpart_svcpart; + $svcdb{$pkgpart} = $part_pkg->part_svc(\@first_svc)->svcdb; + $layermap{$pkgpart_svcpart} = $svcdb{$pkgpart}; +} + +my @options = ( '', map $pkgpart_svcpart{ $_->pkgpart }, @part_pkg ); +my %labels = ( '' => ( $opt{'empty_label'} || '(none)' ), + map { $pkgpart_svcpart{ $_->pkgpart } => $_->pkg_comment } + @part_pkg + ); + +my $layer_callback = sub { + my $layer = shift; + #$layer_fields, $layer_values, $layer_prefix + +# my( $pkgpart, $svcpart ) = split('_', $layer); +# my $svcdb = $svcdb{$pkgpart}; + my $svcdb = $layer; + + return '' unless $svcdb; #'<BR><BR><BR><BR><BR>' + + #full path cause we're being slung around as a coderef (mason closures?) + include("/edit/cust_main/first_pkg/$svcdb.html", %opt, ); +}; + +</%init> diff --git a/httemplate/edit/cust_main/first_pkg/svc_acct.html b/httemplate/edit/cust_main/first_pkg/svc_acct.html new file mode 100644 index 0000000..150d4c0 --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg/svc_acct.html @@ -0,0 +1,88 @@ +<% ntable("#cccccc") %> + + <TR> + <TD ALIGN="right">Username</TD> + <TD> + <INPUT TYPE = "text" + NAME = "username" + VALUE = "<% $opt{'username'} %>" + SIZE = <% $ulen2 %> + MAXLENGTH = <% $ulen %> + > + </TD> + </TR> + + <TR> + <TD ALIGN="right">Domain</TD> + <TD> + <SELECT NAME="domsvc"> + <OPTION>(none)</OPTION> + </SELECT> + </TD> + </TR> + + <TR> + <TD ALIGN="right">Password</TD> + <TD> + <INPUT TYPE = "text" + NAME = "_password" + VALUE = "<% $opt{'password'} %>" + SIZE = <% $pmax2 %> + MAXLENGTH = <% $passwordmax %>> +% unless ( $opt{'password_verify'} ) { + (blank to generate) +% } + </TD> + </TR> + +% if ( $opt{'password_verify'} ) { + <TR> + <TD ALIGN="right">Re-enter Password</TD> + <TD> + <INPUT TYPE = "text" + NAME = "_password2" + VALUE = "<% $opt{'password2'} %>" + SIZE = <% $pmax2 %> + MAXLENGTH = <% $passwordmax %>> + </TD> + </TR> +% } + +% if ( $conf->exists('security_phrase') ) { + <TR> + <TD ALIGN="right">Security Phrase</TD> + <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="<% $opt{'sec_phrase'} %>"> + </TD> + </TR> +% } else { + <INPUT TYPE="hidden" NAME="sec_phrase" VALUE=""> +% } + +% if ( $conf->exists('svc_acct-disable_access_number') ) { + <INPUT TYPE="hidden" NAME="popnum" VALUE=""> +% } else { + <TR> + <TD ALIGN="right">Access number</TD> +%# XXX should gain "area code" selection and labels on the dropdowns + <TD><% FS::svc_acct_pop::popselector($opt{'popnum'}) %></TD> + </TR> +% } + +</TABLE> + +<%init> + +#use FS::svc_acct_pop; + +my( %opt ) = @_; + +my $conf = new FS::Conf; + +#false laziness: (mostly) copied from edit/svc_acct.cgi +#$ulen = $svc_acct->dbdef_table->column('username')->length; +my $ulen = dbdef->table('svc_acct')->column('username')->length; +my $ulen2 = $ulen+2; +my $passwordmax = $conf->config('passwordmax') || 8; +my $pmax2 = $passwordmax + 2; + +</%init> diff --git a/httemplate/edit/cust_main/first_pkg/svc_phone.html b/httemplate/edit/cust_main/first_pkg/svc_phone.html new file mode 100644 index 0000000..70e013e --- /dev/null +++ b/httemplate/edit/cust_main/first_pkg/svc_phone.html @@ -0,0 +1,82 @@ +<% ntable("#cccccc") %> + +%#XXX this should be hidden or something in most/all cases + <TR> + <TD ALIGN="right" ID="countrycode_label_td">Country code</TD> + <TD ID="countrycode_td"> + <INPUT TYPE = "text" + NAME = "countrycode" + ID = "countrycode" + VALUE = "<% $opt{'countrycode'} %>" + SIZE = 4 + MAXLENGTH = 3 + > + </TD> + </TR> + +%#we don't know the svcpart until the dropdown is changed :/ +%#<% include('/elements/tr-select-did.html', +%# 'label' => 'Phone number', +%# 'curr_value' => $opt{'phonenum'}, +%# ) +%#%> + <TR> + <TD ALIGN="right" ID="phonenum_label_td">Phone Number</TD> + <TD ID="phonenum_td"> + <INPUT TYPE = "text" + NAME = "phonenum" + ID = "phonenum" + VALUE = "<% $opt{'phonenum'} %>" + SIZE = 21 + MAXLENGTH = 20 + > + </TD> + </TR> + + <TR> + <TD ALIGN="right" ID="sip_password_label_td">SIP password</TD> + <TD ID="sip_password_td"> + <INPUT TYPE = "text" + NAME = "sip_password" + ID = "sip_password" + VALUE = "<% $opt{'sip_password'} %>" + MAXLENGTH = 80 + > + </TD> + </TR> + + <TR> + <TD ALIGN="right" ID="pin_label_td">Voicemail PIN</TD> + <TD ID="pin_td"> + <INPUT TYPE = "text" + NAME = "pin" + ID = "pin" + VALUE = "<% $opt{'pin'} %>" + SIZE = 5 + MAXLENGTH = 4 + > + </TD> + </TR> + +%#XXX this should be hidden or something in most/all cases + <TR> + <TD ALIGN="right" ID="phone_name_label_td">Name</TD> + <TD ID="phone_name_td"> + <INPUT TYPE = "text" + NAME = "phone_name" + ID = "phone_name" + VALUE = "<% $opt{'phone_name'} %>" + MAXLENGTH = 80 + > + </TD> + </TR> + +</TABLE> + +<%init> + +my( %opt ) = @_; + +#my $conf = new FS::Conf; + +</%init> diff --git a/httemplate/edit/cust_main/select-domain.html b/httemplate/edit/cust_main/select-domain.html deleted file mode 100644 index bec1e83..0000000 --- a/httemplate/edit/cust_main/select-domain.html +++ /dev/null @@ -1,67 +0,0 @@ - -<% include('/elements/xmlhttp.html', - 'url' => $p.'misc/svc_acct-domains.cgi', - 'subs' => [ $opt{'prefix'}. 'get_domains' ], - ) -%> - -<SCRIPT TYPE="text/javascript"> - - function selopt(what,value,text,selected) { - var optionName = new Option(text, value, false, selected); - var length = what.length; - what.options[length] = optionName; - } - - function <% $opt{'prefix'} %>pkgpart_svcpart_changed(what,selected) { - - pkgpart_svcpart = what.options[what.selectedIndex].value; - - function <% $opt{'prefix'} %>update_domains(domains) { - - // blank the current domain list - for ( var i = what.form.<% $opt{'prefix'} %>domsvc.length; i >= 0; i-- ) - what.form.<% $opt{'prefix'} %>domsvc.options[i] = null; - - // add the new domains - var domainArray = eval('(' + domains + ')' ); - for ( var s = 0; s < domainArray.length; s=s+2 ) { - var domainLabel = domainArray[s+1]; - if ( domainLabel == "" ) - domainLabel = '(n/a)'; - selopt(what.form.<% $opt{'prefix'} %>domsvc, domainArray[s], domainLabel, (domainArray[s] == selected) ? true : false); - } - - } - - // go get the new domains - <% $opt{'prefix'} %>get_domains( pkgpart_svcpart, <% $opt{'prefix'} %>update_domains ); - - } - -</SCRIPT> - -<SELECT NAME="<% $opt{'prefix'} %>pkgpart_svcpart" onchange="<% $opt{'prefix'} %>pkgpart_svcpart_changed(this,0);" > - <OPTION VALUE="">(none) - -% foreach my $part_pkg ( @part_pkg ) { - - <OPTION VALUE="<% $part_pkg->pkgpart. "_". $part_pkg->svcpart('svc_acct') %>"<% ( $opt{saved_pkgpart} && $part_pkg->pkgpart == $opt{saved_pkgpart} ) ? ' SELECTED' : '' %>><% $part_pkg->pkg. " - ". $part_pkg->comment %> - -% } - -</SELECT> -<SCRIPT> - pkgpart_svcpart_changed(document.bottomform.pkgpart_svcpart, <% $opt{saved_domsvc} %>); -</SCRIPT> - -<%init> -my %opt = @_; -foreach my $opt (qw( svc_part pkgparts saved_pkgpart saved_domsvc prefix)) { - $opt{$_} = '' unless exists($opt{$_}) && defined($opt{$_}); -} -$opt{saved_domsvc} = 0 unless $opt{saved_domsvc}; -my @part_pkg = @{$opt{'pkgparts'}}; - -</%init> - diff --git a/httemplate/edit/cust_main/top_misc.html b/httemplate/edit/cust_main/top_misc.html new file mode 100644 index 0000000..0410506 --- /dev/null +++ b/httemplate/edit/cust_main/top_misc.html @@ -0,0 +1,97 @@ +<% &ntable("#cccccc") %> + +%# agent +<% include('/elements/tr-select-agent.html', + 'curr_value' => $cust_main->agentnum, + 'label' => "<B>${r}Agent</B>", + 'empty_label' => 'Select agent', + 'disable_empty' => ( $cust_main->agentnum ? 1 : 0 ), + ) +%> + +%# agent_custid +% if ( $conf->exists('cust_main-edit_agent_custid') ) { + + <TR> + <TD ALIGN="right">Customer identifier</TD> + <TD><INPUT TYPE="text" NAME="agent_custid" VALUE="<% $cust_main->agent_custid %>"></TD> + </TR> + +% } else { + + <INPUT TYPE="hidden" NAME="agent_custid" VALUE="<% $cust_main->agent_custid %>"> + +% } + +%# referral (advertising source) +%my $refnum = $cust_main->refnum || $conf->config('referraldefault') || 0; +%if ( $custnum && ! $conf->exists('editreferrals') ) { + + <INPUT TYPE="hidden" NAME="refnum" VALUE="<% $refnum %>"> + +% } else { + + <% include('/elements/tr-select-part_referral.html', + 'curr_value' => $refnum + ) + %> +% } + + +%# referring customer +%my $referring_cust_main = ''; +%if ( $cust_main->referral_custnum +% and $referring_cust_main = +% qsearchs('cust_main', { custnum => $cust_main->referral_custnum } ) +%) { + + <TR> + <TD ALIGN="right">Referring customer</TD> + <TD> + <A HREF="<% popurl(1) %>/cust_main.cgi?<% $cust_main->referral_custnum %>"><% $cust_main->referral_custnum %>: <% $referring_cust_main->name %></A> + </TD> + </TR> + <INPUT TYPE="hidden" NAME="referral_custnum" VALUE="<% $cust_main->referral_custnum %>"> +% } elsif ( ! $conf->exists('disable_customer_referrals') ) { + + + <TR> + <TD ALIGN="right">Referring customer</TD> + <TD> + <!-- <INPUT TYPE="text" NAME="referral_custnum" VALUE=""> --> + <% include('/elements/search-cust_main.html', + 'field_name' => 'referral_custnum', + ) + %> + </TD> + </TR> +% } else { + + + <INPUT TYPE="hidden" NAME="referral_custnum" VALUE=""> +% } + +%# signup date +% if ( $conf->exists('cust_main-edit_signupdate') ) { + <% include('/elements/tr-input-date-field.html', { + 'name' => 'signupdate', + 'value' => $cust_main->signupdate, + 'label' => 'Signup date', + 'format' => $conf->config('date_format') || "%m/%d/%Y", + }) + %> +% } + +</TABLE> + +<%init> + +my( $cust_main, %opt ) = @_; + +my $custnum = $opt{'custnum'}; + +my $conf = new FS::Conf; + +my $r = qq!<font color="#ff0000">*</font> !; + +</%init> diff --git a/httemplate/edit/cust_main_attach.cgi b/httemplate/edit/cust_main_attach.cgi new file mode 100755 index 0000000..43d2e29 --- /dev/null +++ b/httemplate/edit/cust_main_attach.cgi @@ -0,0 +1,59 @@ +<% include('/elements/header-popup.html', "$action File Attachment") %> + +<% include('/elements/error.html') %> + +<FORM ACTION="<% popurl(1) %>process/cust_main_attach.cgi" METHOD=POST ENCTYPE="multipart/form-data"> +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> +<INPUT TYPE="hidden" NAME="attachnum" VALUE="<% $attachnum %>"> + +<BR><BR> + +% if(defined $attach) { +Filename <INPUT TYPE="text" NAME="filename" VALUE="<% $attach->filename %>"><BR> +MIME type <INPUT TYPE="text" NAME="mime_type" VALUE="<% $attach->mime_type %>"<BR> +Size: <% $attach->size %><BR> + +% } +% else { # !defined $attach + +Filename <INPUT TYPE="file" NAME="file"><BR> + +% } + +<BR> +<INPUT TYPE="submit" NAME="submit" + VALUE="<% $attachnum ? "Apply Changes" : "Upload File" %>"> + +% if(defined $attach and $curuser->access_right('Delete attachment')) { +<BR> +<INPUT TYPE="submit" NAME="delete" value="Delete File"> +% } + +</FORM> +</BODY> +</HTML> + +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; +my $attachnum = ''; +my $attach; +if ( $cgi->param('error') ) { + #$comment = $cgi->param('comment'); +} elsif ( $cgi->param('attachnum') =~ /^(\d+)$/ ) { + $attachnum = $1; + die "illegal query ". $cgi->keywords unless $attachnum; + $attach = qsearchs('cust_attachment', { 'attachnum' => $attachnum }); + die "no such attachment: ". $attachnum unless $attach; +} + +$cgi->param('custnum') =~ /^(\d+)$/ or die "illegal custnum"; +my $custnum = $1; + +my $action = $attachnum ? 'Edit' : 'Add'; + +die "access denied" + unless $curuser->access_right("$action attachment"); + +</%init> + diff --git a/httemplate/edit/cust_pay.cgi b/httemplate/edit/cust_pay.cgi index 3c28774..07e5198 100755 --- a/httemplate/edit/cust_pay.cgi +++ b/httemplate/edit/cust_pay.cgi @@ -72,6 +72,16 @@ Payment % } </TR> +% if ( $conf->exists('pkg-balances') ) { + <% include('/elements/tr-select-cust_pkg-balances.html', + 'custnum' => $custnum, + 'cgi' => $cgi + ) + %> +% } else { + <INPUT TYPE="hidden" NAME="pkgnum" VALUE=""> +% } + </TABLE> <BR> @@ -95,7 +105,7 @@ my $money_char = $conf->config('money_char') || '$'; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Post payment'); -my($link, $linknum, $paid, $payby, $payinfo, $_date); +my($link, $linknum, $paid, $payby, $payinfo, $_date); if ( $cgi->param('error') ) { $link = $cgi->param('link'); $linknum = $cgi->param('linknum'); @@ -131,7 +141,7 @@ if ( $link eq 'invnum' ) { my $cust_bill = qsearchs('cust_bill', { 'invnum' => $linknum } ) or die "unknown invnum $linknum"; $custnum = $cust_bill->custnum; -} elsif ( $link eq 'custnum' ) { +} elsif ( $link eq 'custnum' || $link eq 'popup' ) { $custnum = $linknum; } diff --git a/httemplate/edit/cust_pkg.cgi b/httemplate/edit/cust_pkg.cgi index f927e10..dd1ed33 100755 --- a/httemplate/edit/cust_pkg.cgi +++ b/httemplate/edit/cust_pkg.cgi @@ -128,10 +128,10 @@ my %all_comment = (); #} foreach (qsearch('part_pkg', {} )) { $all_pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); - $all_comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment'); + $all_comment{ $_ -> getfield('pkgpart') } = $_->custom_comment; next if $_->disabled; $pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); - $comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment'); + $comment{ $_ -> getfield('pkgpart') } = $_->custom_comment; } my($custnum, %remove_pkg); diff --git a/httemplate/edit/cust_tax_adjustment.html b/httemplate/edit/cust_tax_adjustment.html new file mode 100644 index 0000000..9d4afbc --- /dev/null +++ b/httemplate/edit/cust_tax_adjustment.html @@ -0,0 +1,102 @@ +<% include('/elements/header-popup.html', 'Tax adjustment' ) %> + +<% include('/elements/error.html') %> + +<SCRIPT TYPE="text/javascript"> + +function enable_tax_adjustment () { + if ( document.TaxAdjustmentForm.amount.value + && document.TaxAdjustmentForm.taxname.selectedIndex > 0 ) { + document.TaxAdjustmentForm.submit.disabled = false; + } else { + document.TaxAdjustmentForm.submit.disabled = true; + } +} + +function validate_tax_adjustment () { + var comment = document.TaxAdjustmentForm.comment.value; + var comment_regex = /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]*)$/ ; + var amount = document.TaxAdjustmentForm.amount.value; + var amount_regex = /^\s*\$?\s*(\d*(\.?\d{1,2}))\s*$/ ; + var rval = true; + + if ( ! amount_regex.test(amount) ) { + alert('Illegal amount - enter the amount of the tax adjustment, for example, "5" or "43" or "21.46".'); + return false; + } + if ( ! comment_regex.test(comment) ) { + alert('Illegal comment - spaces, letters, numbers, and the following punctuation characters are allowed: . , ! ? @ # $ % & ( ) - + ; : ' + "'" + ' " = [ ]' ); + return false; + } + + return true; +} + +</SCRIPT> + +<FORM ACTION="process/cust_tax_adjustment.html" NAME="TaxAdjustmentForm" ID="TaxAdjustmentForm" METHOD="POST" onsubmit="document.TaxAdjustmentForm.submit.disabled=true;return validate_tax_adjustment();"> + +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> + +<TABLE ID="TaxAdjustmentTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 STYLE="background-color: #cccccc"> + +<TR> + <TD ALIGN="right">Tax </TD> + <TD> + <SELECT NAME="taxname" ID="taxname" onChange="enable_tax_adjustment()" onKeyPress="enable_tax_adjustment()"> + <OPTION VALUE=""></OPTION> +% foreach my $taxname (@taxname) { + <OPTION VALUE="<% $taxname %>"><% $taxname %></OPTION> +% } + </SELECT> + </TD> +</TR> + +<TR> + <TD ALIGN="right">Amount </TD> + <TD> + $<INPUT TYPE="text" NAME="amount" SIZE=6 VALUE="<% $amount %>" onChange="enable_tax_adjustment()" onKeyPress="enable_tax_adjustment()"> + </TD> +</TR> + +<TR> + <TD ALIGN="right">Comment </TD> + <TD> + <INPUT TYPE="text" NAME="comment" SIZE="50" MAXLENGTH="50" VALUE="<% $comment %>" onChange="enable_tax_adjustment()" onKeyPress="enable_tax_adjustment()"> + </TD> +</TR> + +</TABLE> + +<BR> +<INPUT TYPE="submit" ID="submit" NAME="submit" VALUE="Add tax adjustment" <% $cgi->param('error') ? '' :' DISABLED' %>> + +</FORM> + +</BODY> +</HTML> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Add customer tax adjustment'); + +my $sql = 'SELECT DISTINCT(taxname) FROM cust_main_county'; +my $sth = dbh->prepare($sql) or die dbh->errstr; +$sth->execute() or die $sth->errstr; +my @taxname = map { $_->[0] || 'Tax' } @{ $sth->fetchall_arrayref([]) }; + +my $conf = new FS::Conf; + +$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; +my $custnum = $1; + +my $amount = ''; +if ( $cgi->param('amount') =~ /^\s*\$?\s*(\d+(\.\d{1,2})?)\s*$/ ) { + $amount = $1; +} + +$cgi->param('comment') =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]*)$/ + or die 'illegal description'; +my $comment = $1; + +</%init> diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index d18a37d..fd73e03 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -132,37 +132,39 @@ Example: # initialization callbacks ### - ###global callbacks + ###global callbacks, always run if provided - #always run if provided, after decoding long CGI "redirect=" responses but + #after decoding long CGI "redirect=" responses but # before object creation/search # (useful if you have a long form that might trigger redirect= and you need # to do things with $cgi params - they're not decoded in the calling # <%init> block yet) 'begin_callback' = sub { my( $cgi, $fields_listref, $opt_hashref ) = @_; }, - #always run, after the mode-specific object creation/search + #after the mode-specific object creation/search 'end_callback' = sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, - ###mode-specific callbacks + ###mode-specific callbacks. one (and only one) of these four is called + #run when adding + 'new_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, + + #run when editing + 'edit_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, + #run when re-displaying with an error 'error_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, - #run when editing - 'edit_callback' => sub { my( $cgi, $object, $fields_listref ) = @_; }, - + #run when cloning + 'clone_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, + + ###callbacks called in new mode only + # returns a hashref for the new object 'new_hashref_callback' # returns the new object iself (otherwise, ->new is called) 'new_object_callback' - - #run when adding - 'new_callback' => sub { my( $cgi, $object, $fields_listref ) = @_; }, - - #run when cloning - 'clone_callback' => sub { my( $cgi, $object, $fields_listref, $opt_hashref ) = @_; }, ###display callbacks @@ -287,7 +289,8 @@ Example: % foreach grep exists($f->{$_}), qw( hashref agent_virt agent_null_right ); % % if ( $type eq 'tablebreak-tr-title' ) { -% $include_common{'table_id'} = 'TableNumber'. $tablenum++ +% $include_common{'table_id'} = 'TableNumber'. $tablenum++; +% $include_common{'colspan'} = $f->{colspan} if $f->{colspan}; % } % % my $layer_prefix_on = ''; @@ -315,6 +318,27 @@ Example: % @include; % }; % +% my $column_sub = sub { +% my %opt = @_; +% +% my $column = delete($opt{field}); +% my $fieldnum = delete($opt{fieldnum}); +% my $include = delete($opt{type}) || 'text'; +% $include = "input-$include" if $include =~ /^(text|money|percentage)$/; +% +% ( "/elements/$include.html", +% 'field' => $field.'__'.$column.$fieldnum, +% 'id' => $field.'__'.$column.$fieldnum, +% 'layer_prefix' => $field.'__'.$column.$fieldnum.".", +% ( $fieldnum +% ? ('cell_style' => 'border-top:1px solid black') +% : () +% ), +% 'cgi' => $cgi, +% %opt, +% ); +% }; +% % unless ( $type =~ /^column/ ) { % $g_row = 1 if $type eq 'tablebreak-tr-title'; % $g_row++; @@ -380,8 +404,35 @@ Example: % 'layer_values' => $layer_values, % 'cell_style' => ( $fieldnum ? 'border-top:1px solid black' : '' ), % ); +% $existing[0] =~ s(^/elements/tr-)(/elements/); +% my @label = @existing; +% $label[0] = '/elements/tr-td-label.html'; + <% include( @label ) %> + <TD> <% include( @existing ) %> + </TD> + +% if ( $f->{'m2_fields'} ) { +% foreach my $c ( @{ $f->{'m2_fields'} } ) { +% my $column = $c->{field}; +% my @column = &{ $column_sub }( %$c, +% 'fieldnum' => $fieldnum, +% 'curr_value' => $name_obj->$column() +% ); + + <TD id='<% $field %>__<% $column %>_label<% $fieldnum %>' + style='text-align:right;vertical-align:top; + border-top:1px solid black;padding-top:5px;'> + <% $c->{'label'} || '' %> + </TD> + <TD style='border-top:1px solid black;padding-top:3px;'> + <% include( @column ) %> + </TD> +% } +% } + + </TR> % $fieldnum++; % $g_row++; @@ -407,9 +458,40 @@ Example: % 'onchange' => $onchange, % ( $fieldnum ? ('cell_style' => 'border-top:1px solid black') : () ), % ); +% +% if ( $f->{'m2name_table'} || $f->{'m2m_method'} ) { +% $include[0] =~ s(^/elements/tr-)(/elements/); +% my @label = @include; +% $label[0] = '/elements/tr-td-label.html'; + + <% include( @label ) %> + <TD> + <% include( @include ) %> + </TD> + +% if ( $f->{'m2_fields'} ) { +% foreach my $c ( @{ $f->{'m2_fields'} } ) { +% my $column = $c->{field}; +% my @column = &{ $column_sub }( %$c, 'fieldnum' => $fieldnum ); + + <TD id='<% $field %>__<% $column %>_label<% $fieldnum %>' + style='text-align:right;vertical-align:top; + border-top:1px solid black;padding-top:5px;'> + <% $c->{'label'} || '' %> + </TD> + <TD style='border-top:1px solid black;padding-top:3px;'> + <% include( @column ) %> + </TD> +% } +% } + + </TR> + +% } else { - <% include( @include ) %> + <% include( @include ) %> +% } % if ( $f->{'m2name_table'} || $f->{'m2m_method'} ) { <SCRIPT TYPE="text/javascript"> @@ -497,6 +579,39 @@ Example: row.appendChild(widget_cell); +% if ( $f->{'m2_fields'} ) { +% foreach my $c ( @{ $f->{'m2_fields'} } ) { +% my $column = $c->{field}; +% my @column = &{ $column_sub }(%$c, 'fieldnum' => 'MAGIC_NUMBER'); + + var column = <% include(@column, html_only=>1) |js_string %>; + column = column.replace( magic_regex, <%$field%>_fieldnum ); + + var column_label = document.createElement('TD'); + column_label.id = + '<% $field %>__<% $column %>_label' + <%$field%>_fieldnum; + + column_label.style.textAlign = "right"; + column_label.style.verticalAlign = "top"; + column_label.style.borderTop = "1px solid black"; + column_label.style.paddingTop = "5px"; + + column_label.innerHTML = '<% $c->{'label'} || '' %>'; + + row.appendChild(column_label); + + var column_widget = document.createElement('TD'); + + column_widget.style.borderTop = "1px solid black"; + column_widget.style.paddingTop = "3px"; + + column_widget.innerHTML = column; + + row.appendChild(column_widget); + +% } +% } + % if ( $f->{'m2_new_js'} ) { // take out items selected in previous dropdowns var new_element = document.getElementById("<%$field%>" + <%$field%>_fieldnum ); @@ -562,7 +677,7 @@ Example: <BR> -<INPUT TYPE="submit" ID="submit" VALUE="<% ( !$clone && $object->$pkey() ) ? "Apply changes" : "Add $opt{'name'}" %>"> +<INPUT TYPE="submit" ID="submit" VALUE="<% ( !$clone && $object->$pkey() ) ? "Apply changes" : "Add ". ( $opt{'name'} || $opt{'name_singular'} ) %>"> </FORM> @@ -618,7 +733,7 @@ if ( $cgi->param('error') ) { map { $_ => scalar($cgi->param($_)) } fields($table) }); - &{$opt{'error_callback'}}($cgi, $object, $fields, \%opt ) + &{$opt{'error_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'error_callback'}; } elsif ( $cgi->param('clone') =~ /^(\d+)$/ ) { @@ -630,9 +745,10 @@ if ( $cgi->param('error') ) { $qsearch{'extra_sql'} = ' AND '. $opt{'agent_clone_extra_sql'} if $opt{'agent_clone_extra_sql'}; - $object = qsearchs({ %qsearch, 'hashref' => { $pkey => $clone } }); + $object = qsearchs({ %qsearch, 'hashref' => { $pkey => $clone } }) + or die "$pkey $clone not found in $table"; - &{$opt{'clone_callback'}}($cgi, $object, $fields, \%opt ) + &{$opt{'clone_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'clone_callback'}; #$object->$pkey(''); @@ -657,7 +773,7 @@ if ( $cgi->param('error') ) { warn "$table $pkey => $1" if $opt{'debug'}; - &{$opt{'edit_callback'}}($cgi, $object, $fields) + &{$opt{'edit_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'edit_callback'}; } else { #adding @@ -672,7 +788,7 @@ if ( $cgi->param('error') ) { ? &{$opt{'new_object_callback'}}( $cgi, $hashref, $fields, \%opt ) : $class->new( $hashref ); - &{$opt{'new_callback'}}($cgi, $object, $fields) + &{$opt{'new_callback'}}( $cgi, $object, $fields, \%opt ) if $opt{'new_callback'}; } @@ -682,7 +798,7 @@ if ( $cgi->param('error') ) { $opt{action} ||= $object->$pkey() ? 'Edit' : 'Add'; -my $title = $opt{action}. ' '. $opt{name}; +my $title = $opt{action}. ' '. ( $opt{name} || $opt{'name_singular'} ); my $viewall_url = $p . ( $opt{'viewall_dir'} || 'search' ) . "/$table.html"; $viewall_url = $opt{'viewall_url'} if $opt{'viewall_url'}; diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html index 0b64120..ef04bd0 100644 --- a/httemplate/edit/elements/svc_Common.html +++ b/httemplate/edit/elements/svc_Common.html @@ -3,7 +3,7 @@ 'menubar' => [], 'error_callback' => sub { - my( $cgi, $svc_x ) = @_; + my( $cgi, $svc_x, $fields, $opt ) = @_; #$svcnum = $svc_x->svcnum; $pkgnum = $cgi->param('pkgnum'); $svcpart = $cgi->param('svcpart'); @@ -11,11 +11,13 @@ $part_svc = qsearchs( 'part_svc', { svcpart=>$svcpart }); die "No part_svc entry!" unless $part_svc; + label_fixup($part_svc, $opt); + $svc_x->setfield('svcpart', $svcpart); }, 'edit_callback' => sub { - my( $cgi, $svc_x ) = @_; + my( $cgi, $svc_x, $fields, $opt ) = @_; #$svcnum = $svc_x->svcnum; my $cust_svc = $svc_x->cust_svc or die "Unknown (cust_svc) svcnum!"; @@ -25,6 +27,8 @@ $part_svc = qsearchs ('part_svc', { svcpart=>$svcpart }); die "No part_svc entry!" unless $part_svc; + + label_fixup($part_svc, $opt); }, 'new_hashref_callback' => sub { @@ -35,11 +39,13 @@ }, 'new_callback' => sub { - my( $cgi, $svc_x ) = @_;; + my( $cgi, $svc_x, $fields, $opt ) = @_;; $part_svc = qsearchs( 'part_svc', { svcpart=>$svcpart }); die "No part_svc entry!" unless $part_svc; + label_fixup($part_svc, $opt); + #$svcnum=''; $svc_x->set_default_and_fixed; @@ -100,6 +106,22 @@ %opt #pass through/override params ) %> +<%once> + +sub label_fixup { + my( $part_svc, $opt ) = @_; + + #false laziness w/view/svc_Common.html + #override default labels with service-definition labels if applicable + my $labels = $opt->{labels}; # with -> here + foreach my $field ( keys %$labels ) { + my $col = $part_svc->part_svc_column($field); + $labels->{$field} = $col->columnlabel if $col->columnlabel !~ /^\S*$/; + } + +} + +</%once> <%init> my %opt = @_; diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi index 3b51141..c0ff386 100755 --- a/httemplate/edit/part_bill_event.cgi +++ b/httemplate/edit/part_bill_event.cgi @@ -78,7 +78,7 @@ Invoice Event #<% $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)" %> % join("\n", map { % '<OPTION VALUE="'. $_->pkgpart. '"'. % ( $selected{$_->pkgpart} ? ' SELECTED' : '' ). -% '>'. $_->pkg. ' - '. $_->comment +% '>'. $_->pkg_comment % } qsearch('part_pkg', { 'disabled' => '' } ) ). % '</SELECT>'; %} @@ -178,7 +178,7 @@ Invoice Event #<% $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)" %> % 'cancel' => { % 'name' => 'Cancel', % 'code' => '$cust_main->cancel(reason => %%%creason%%%);', -% 'weight' => 10, +% 'weight' => 80, #10, % 'reason' => 'C', % }, % @@ -191,7 +191,7 @@ Invoice Event #<% $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)" %> % 'comp' => { % 'name' => 'Pay invoice with a complimentary "payment"', % 'code' => '$cust_bill->comp();', -% 'weight' => 30, +% 'weight' => 90, #30, % }, % % 'credit' => { diff --git a/httemplate/edit/part_device.html b/httemplate/edit/part_device.html new file mode 100644 index 0000000..4f2fe93 --- /dev/null +++ b/httemplate/edit/part_device.html @@ -0,0 +1,16 @@ +<% include( 'elements/edit.html', + 'name' => 'Phone device type', + 'table' => 'part_device', + 'labels' => { + 'devicepart' => 'Part number', + 'devicename' => 'Device name', + }, + 'viewall_dir' => 'browse', + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +</%init> diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi index d579797..8b697e1 100644 --- a/httemplate/edit/part_export.cgi +++ b/httemplate/edit/part_export.cgi @@ -79,13 +79,28 @@ my $widget = new HTML::Widgets::SelectLayers( ); $html .= qq!<TR><TD ALIGN="right">$label</TD><TD>!; if ( $type eq 'select' ) { - $html .= qq!<SELECT NAME="$option">!; - foreach my $select_option ( @{$optinfo->{options}} ) { + my $size = defined($optinfo->{size}) ? " SIZE=" . $optinfo->{size} : ''; + my $multi = defined($optinfo->{multi}) ? ' MULTIPLE' : ''; + $html .= qq!<SELECT NAME="$option"$multi$size>!; + my @values = split '\s+', $value if $multi; + my @options; + if (defined($optinfo->{option_values})) { + my $valsub = $optinfo->{option_values}; + @options = &$valsub(); + } elsif (defined($optinfo->{options})) { + @options = @{$optinfo->{options}}; + } + foreach my $select_option ( @options ) { #if ( ref($select_option) ) { #} else { - my $selected = $select_option eq $value ? ' SELECTED' : ''; + my $selected = ($multi ? grep {$_ eq $select_option} @values : $select_option eq $value ) ? ' SELECTED' : ''; + my $label = $select_option; + if (defined($optinfo->{option_label})) { + my $labelsub = $optinfo->{option_label}; + $label = &$labelsub($select_option); + } $html .= qq!<OPTION VALUE="$select_option"$selected>!. - qq!$select_option</OPTION>!; + qq!$label</OPTION>!; #} } $html .= '</SELECT>'; diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index f404699..690e884 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -37,6 +37,8 @@ 'taxproduct_select'=> 'Tax products', 'plan' => 'Price plan', 'disabled' => 'Disable new orders', + 'setup_cost' => 'Setup cost', + 'recur_cost' => 'Recur cost', 'pay_weight' => 'Payment weight', 'credit_weight' => 'Credit weight', 'agentnum' => 'Agent', @@ -44,6 +46,7 @@ 'recur_fee' => 'Recurring fee', 'bill_dst_pkgpart' => 'Include line item(s) from package', 'svc_dst_pkgpart' => 'Include services of package', + 'report_option' => 'Report classes', }, 'fields' => [ @@ -56,6 +59,8 @@ sub { shift->param('pkgnum') }, }, + { field=>'custom', type=>'hidden' }, + { type => 'columnstart' }, { field => 'pkg', @@ -131,10 +136,10 @@ { field=>'promo_code', type=>'text', size=>15 }, { type => 'tablebreak-tr-title', - value => 'Line-item revenue recogition', #better name? + value => 'Cost tracking', #better name? }, - { field=>'pay_weight', type=>'text', size=>6 }, - { field=>'credit_weight', type=>'text', size=>6 }, + { field=>'setup_cost', type=>'money', }, + { field=>'recur_cost', type=>'money', }, { type => 'columnnext' }, @@ -148,10 +153,31 @@ }, }, + { type => 'tablebreak-tr-title', + value => 'Line-item revenue recogition', #better name? + }, + { field=>'pay_weight', type=>'text', size=>6 }, + { field=>'credit_weight', type=>'text', size=>6 }, + + { type => 'columnend' }, - { 'type' => 'tablebreak-tr-title', - 'value' => 'Pricing add-ons', + { 'type' => $census ? 'tablebreak-tr-title' + : 'hidden', + 'value' => 'Optional report classes', + 'field' => 'census_title', + }, + { 'field' => 'report_option', + 'type' => $census ? 'select-table' : 'hidden', + 'table' => 'part_pkg_report_option', + 'name_col' => 'name', + 'multiple' => 1, + }, + + + { 'type' => 'tablebreak-tr-title', + 'value' => 'Pricing add-ons', + 'colspan' => 4, }, { 'field' => 'bill_dst_pkgpart', 'type' => 'select-part_pkg', @@ -160,6 +186,13 @@ 'm2m_dstcol' => 'dst_pkgpart', 'm2_error_callback' => &{$m2_error_callback_maker}('bill'), + 'm2_fields' => [ { 'field' => 'hidden', + 'type' => 'checkbox', + 'value' => 'Y', + 'curr_value' => '', + 'label' => 'Bundle', + }, + ], }, { type => 'tablebreak-tr-title', @@ -208,12 +241,12 @@ my $disabled_type = $acl_edit_either ? 'checkbox' : 'hidden'; my $agent_clone_extra_sql = ' ( '. FS::part_pkg->curuser_pkgs_sql. - #kludge to clone custom customer packages you otherwise couldn't see - " OR ( part_pkg.disabled = 'Y' AND part_pkg.comment LIKE '(CUSTOM)%' ) ". + " OR ( part_pkg.custom = 'Y' ) ". ' ) '; my $conf = new FS::Conf; my $taxproducts = $conf->exists('enable_taxproducts'); +my $census = scalar( qsearch( 'part_pkg_report_option', {} ) ); #XXX # - tr-part_pkg_freq: month_increments_only (from price plans) @@ -291,14 +324,27 @@ my $edit_callback = sub { (@agent_type) = map {$_->typenum} qsearch('type_pkgs',{'pkgpart'=>$1}); + my @report_option = (); foreach ($object->options) { /^usage_taxproductnum_(\d+)$/ && ($taxproductnums{$1} = 1); + /^report_option_(\d+)$/ && (push @report_option, $1); } foreach ($object->part_pkg_taxoverride) { $taxproductnums{$_->usage_class} = 1 if $_->usage_class; } + $cgi->param('report_option', join(',', @report_option)); + foreach my $field ( @$fields ) { + next unless ( + ref($field) eq 'HASH' && + $field->{field} && + $field->{field} eq 'report_option' + ); + #$field->{curr_value} = join(',', @report_option); + $field->{value} = join(',', @report_option); + } + %options = $object->options; $object->set($_ => $object->option($_)) @@ -328,9 +374,8 @@ my $clone_callback = sub { $opt->{action} = 'Custom'; #my $part_pkg = $clone_part_pkg->clone; - #this is all clone did anyway - $object->comment( '(CUSTOM) '. $object->comment ) - unless $object->comment =~ /^\(CUSTOM\) /; + #this is all clone does anyway + $object->custom('Y'); $object->disabled('Y'); @@ -348,16 +393,26 @@ my $m2_error_callback_maker = sub { my $link_type = shift; #yay closures return sub { my( $cgi, $object ) = @_; - map { - new FS::part_pkg_link { - 'link_type' => $link_type, - 'src_pkgpart' => $object->pkgpart, - 'dst_pkgpart' => $_, - }; - } - grep $_, - map $cgi->param($_), - grep /^${link_type}_dst_pkgpart(\d+)$/, $cgi->param; + my $num; + map { + + if ( /^${link_type}_dst_pkgpart(\d+)$/ && + ( my $dst = $cgi->param("${link_type}_dst_pkgpart$1") ) ) + { + + my $hidden = $cgi->param("${link_type}_dst_pkgpart__hidden$1") + || ''; + new FS::part_pkg_link { + 'link_type' => $link_type, + 'src_pkgpart' => $object->pkgpart, + 'dst_pkgpart' => $dst, + 'hidden' => $hidden, + }; + } else { + (); + } + } + $cgi->param; }; }; diff --git a/httemplate/edit/part_pkg_report_option.html b/httemplate/edit/part_pkg_report_option.html new file mode 100644 index 0000000..a6f8e57 --- /dev/null +++ b/httemplate/edit/part_pkg_report_option.html @@ -0,0 +1,23 @@ +<% include( 'elements/edit.html', + 'name' => 'Package optional report class', + 'table' => 'part_pkg_report_option', + 'fields' => [ + 'name', + { field=>'num', type=>'hidden' }, + { field=>'disabled', type=>'checkbox', value=>'Y', }, + ], + 'labels' => { + 'num' => 'Class number', + 'name' => 'Class name', + 'disabled' => 'Disable class', + }, + 'viewall_dir' => 'browse', + ) + +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +</%init> diff --git a/httemplate/edit/part_pkg_taxclass.html b/httemplate/edit/part_pkg_taxclass.html index e767057..ad03044 100644 --- a/httemplate/edit/part_pkg_taxclass.html +++ b/httemplate/edit/part_pkg_taxclass.html @@ -1,32 +1,23 @@ -<% include('/elements/header.html', "$action taxclass") %> - -<% include('/elements/error.html') %> - -<FORM ACTION="<% $p1 %>process/part_pkg_taxclass.html" METHOD=POST> - -<INPUT TYPE="hidden" NAME="taxclassnum" VALUE=""> - -Tax class <INPUT TYPE="text" NAME="taxclass" VALUE="<% $taxclass |h %>"> - -<BR><BR> -<INPUT TYPE="submit" VALUE="<% $action %> taxclass"> - -</FORM> - -<% include('/elements/footer.html') %> - +<% include('elements/edit.html', + 'name_singular' => 'tax class', + 'table' => 'part_pkg_taxclass', + 'labels' => { + 'taxclassnum' => 'Tax class', + 'taxclass' => 'Tax class', + 'disabled' => 'Disabled', + }, + 'fields' => [ 'taxclass', + { 'field' => 'disabled', + 'type' => 'checkbox', + 'value' => 'Y', + }, + ], + 'viewall_dir' => 'browse', + ) +%> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my $taxclass = ''; -if ( $cgi->param('error') ) { - $taxclass = $cgi->param('taxclass'); -} - -my $action = 'Add'; - -my $p1 = popurl(1); - </%init> diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index e0fb615..7970343 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -122,6 +122,7 @@ that field. % $html .= include('/elements/table-grid.html', 'cellpadding' => 4 ). % '<TR>'. % '<TH CLASS="grid" BGCOLOR="#cccccc">Field</TH>'. +% '<TH CLASS="grid" BGCOLOR="#cccccc">Label</TH>'. % '<TH CLASS="grid" BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH>'. % '</TR>'; % @@ -131,7 +132,14 @@ that field. % % #yucky kludge % my @fields = defined( dbdef->table($layer) ) -% ? grep { $_ ne 'svcnum' } fields($layer) +% ? grep { +% $_ ne 'svcnum' && +% ( !FS::part_svc->svc_table_fields($layer) +% ->{$_}->{disable_part_svc_column} || +% $part_svc->part_svc_column($_)->columnflag +% ) +% } +% fields($layer) % : (); % push @fields, 'usergroup' if $layer eq 'svc_acct'; #kludge % $part_svc->svcpart($clone) if $clone; #haha, undone below @@ -139,13 +147,15 @@ that field. % % foreach my $field (@fields) { % -% #my $def = $defs{$layer}{$field}; +% #a few lines of false laziness w/browse/part_svc.cgi % my $def = FS::part_svc->svc_table_fields($layer)->{$field}; -% my $label = $def->{'def_label'} || $def->{'label'}; +% my $def_info = $def->{'def_info'}; % my $formatter = $def->{'format'} || sub { shift }; +% % my $part_svc_column = $part_svc->part_svc_column($field); +% my $label = $part_svc_column->columnlabel || $def->{'label'}; % my $value = &$formatter($part_svc_column->columnvalue); -% my $flag = $part_svc_column->columnflag; +% my $flag = $part_svc_column->columnflag; % % if ( $bgcolor eq $bgcolor1 ) { % $bgcolor = $bgcolor2; @@ -153,9 +163,12 @@ that field. % $bgcolor = $bgcolor1; % } % -% $html .= qq!<TR><TD CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">!. -% ( $label || $field ). +% $html .= qq!<TR><TD ROWSPAN=2 CLASS="grid" BGCOLOR="$bgcolor" ALIGN="right">!. +% ( $def->{'label'} || $field ). % "</TD>"; +% +% $html .= qq!<TD ROWSPAN=2 CLASS="grid" BGCOLOR="$bgcolor"><INPUT NAME="${layer}__${field}_label" VALUE="!. encode_entities($label). '" STYLE="text-align:right"></TD>'; +% % $flag = '' if $def->{type} eq 'disabled'; % % $html .= qq!<TD CLASS="grid" BGCOLOR="$bgcolor">!; @@ -295,6 +308,15 @@ that field. % } % % $html .= "</TD></TR>\n"; + +% $def_info = "($def_info)" if $def_info; +% $html .= +% qq!<TR>!. +% qq! <TD COLSPAN=2 BGCOLOR="$bgcolor" ALIGN="center" !. +% qq! STYLE="padding:0; border-top: none">!. +% qq! <FONT SIZE="-1"><I>$def_info</I></FONT>!. +% qq! </TD>!. +% qq!</TR>\n!; % % } #foreach my $field (@fields) { % diff --git a/httemplate/edit/payment_gateway.html b/httemplate/edit/payment_gateway.html index e3893cf..4c7bae1 100644 --- a/httemplate/edit/payment_gateway.html +++ b/httemplate/edit/payment_gateway.html @@ -1,132 +1,134 @@ -<% include("/elements/header.html","$action Payment gateway", menubar( - 'View all payment gateways' => $p. 'browse/payment_gateway.html', -)) %> - -<% include('/elements/error.html') %> - -<FORM ACTION="<%popurl(1)%>process/payment_gateway.html" METHOD=POST> -<INPUT TYPE="hidden" NAME="gatewaynum" VALUE="<% $payment_gateway->gatewaynum %>"> -Gateway #<% $payment_gateway->gatewaynum || "(NEW)" %> - -<% ntable('#cccccc', 2, '') %> - -<TR> - <TH ALIGN="right">Gateway: </TH> - <TD> -% if ( $payment_gateway->gatewaynum ) { - - - <% $payment_gateway->gateway_module %> - <INPUT TYPE="hidden" NAME="gateway_module" VALUE="<% $payment_gateway->gateway_module %>"> -% } else { - - - <SELECT NAME="gateway_module" SIZE=1> -% foreach my $module ( qw( -% 2CheckOut -% AuthorizeNet -% BankOfAmerica -% Beanstream -% Capstone -% Cardstream -% CashCow -% CyberSource -% eSec -% eSelectPlus -% Exact -% iAuthorizer -% IPaymentTPG -% Jettis -% LinkPoint -% MerchantCommerce -% Network1Financial -% OCV -% OpenECHO -% PayConnect -% PayflowPro -% PaymentsGateway -% PXPost -% SecureHostingUPG -% Skipjack -% StGeorge -% SurePay -% TCLink -% TransactionCentral -% TransFirsteLink -% VirtualNet -% ) ) { -% - - <OPTION VALUE="<% $module %>"><% $module %> -% } - - </SELECT> +<% include( 'elements/edit.html', + 'table' => 'payment_gateway', + 'name_singular' => 'Payment gateway', + 'viewall_dir' => 'browse', + 'fields' => $fields, + 'field_callback' => $field_callback, + 'labels' => { + 'gatewaynum' => 'Gateway #', + 'gateway_module' => 'Gateway', + 'gateway_username' => 'Username', + 'gateway_password' => 'Password', + 'gateway_action' => 'Action', + 'gateway_options' => 'Options: (Name/Value pairs, one element per line)', + 'gateway_callback_url' => 'Callback URL', + }, + ) +%> + + +<SCRIPT TYPE="text/javascript"> + var gatewayNamespace = new Array; + +% foreach my $module ( sort { lc($a) cmp lc ($b) } keys %modules ) { + gatewayNamespace.push('<% $modules{$module} %>') % } + // document.getElementById('gateway_namespace').value = gatewayNamespace[0]; + function setNamespace(what) { + document.getElementById('gateway_namespace').value = + gatewayNamespace[what.selectedIndex]; + } - </TD> -</TR> - -<TR> - <TH ALIGN="right">Username: </TH> - <TD><INPUT TYPE="text" NAME="gateway_username" VALUE="<% $payment_gateway->gateway_username %>"></TD> -</TR> - -<TR> - <TH ALIGN="right">Password: </TH> - <TD><INPUT TYPE="text" NAME="gateway_password" VALUE="<% $payment_gateway->gateway_password %>"></TD> -</TR> - -<TR> - <TH ALIGN="right">Action: </TH> - <TD> - <SELECT NAME="gateway_action" SIZE=1> -% foreach my $action ( -% 'Normal Authorization', -% 'Authorization Only', -% 'Authorization Only, Post Authorization', -% ) { -% - - <OPTION VALUE="<% $action %>"<% $action eq $payment_gateway->gateway_action ? ' SELECTED' : '' %>><% $action %> -% } - - </SELECT> - </TD> -</TR> - -<TR> - <TH ALIGN="right">Options: (Name/Value pairs, one element per line)</TH> - <TD> - <TEXTAREA ROWS="5" NAME="gateway_options"><% join("\r", $payment_gateway->options ) %></TEXTAREA> - </TD> -</TR> - -</TABLE> - -<BR><INPUT TYPE="submit" VALUE="<% $payment_gateway->gatewaynum ? "Apply changes" : "Add gateway" %>"> - </FORM> - -<% include('/elements/footer.html') %> +</SCRIPT> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my $payment_gateway; -if ( $cgi->param('error') ) { - $payment_gateway = new FS::payment_gateway ( { - map { $_, scalar($cgi->param($_)) } fields('payment_gateway') - } ); -} elsif ( $cgi->keywords ) { - my($query) = $cgi->keywords; - $query =~ /^(\d+)$/; - $payment_gateway = qsearchs( 'payment_gateway', { 'gatewaynum' => $1 } ); -} else { #adding - $payment_gateway = new FS::payment_gateway {}; -} -my $action = $payment_gateway->gatewaynum ? 'Edit' : 'Add'; -#my $hashref = $payment_gateway->hashref; +my %modules = ( + '2CheckOut' => 'Business::OnlinePayment', + 'AuthorizeNet' => 'Business::OnlinePayment', + 'BankOfAmerica' => 'Business::OnlinePayment', #deprecated? + 'Beanstream' => 'Business::OnlinePayment', + 'Capstone' => 'Business::OnlinePayment', + 'Cardstream' => 'Business::OnlinePayment', + 'CashCow' => 'Business::OnlinePayment', + 'CyberSource' => 'Business::OnlinePayment', + 'eSec' => 'Business::OnlinePayment', + 'eSelectPlus' => 'Business::OnlinePayment', + 'Exact' => 'Business::OnlinePayment', + 'iAuthorizer' => 'Business::OnlinePayment', + 'Ingotz' => 'Business::OnlinePayment', + 'InternetSecure' => 'Business::OnlinePayment', + 'Interswitchng' => 'Business::OnlineThirdPartyPayment', + 'IPaymentTPG' => 'Business::OnlinePayment', + 'IPPay' => 'Business::OnlinePayment', + 'Iridium' => 'Business::OnlinePayment', + 'Jettis' => 'Business::OnlinePayment', + 'LinkPoint' => 'Business::OnlinePayment', + 'MerchantCommerce' => 'Business::OnlinePayment', + 'Network1Financial' => 'Business::OnlinePayment', + 'OCV' => 'Business::OnlinePayment', + 'OpenECHO' => 'Business::OnlinePayment', + 'PayConnect' => 'Business::OnlinePayment', + 'PayflowPro' => 'Business::OnlinePayment', + 'PaymenTech' => 'Business::OnlinePayment', + 'PaymentsGateway' => 'Business::OnlinePayment', + 'PayPal' => 'Business::OnlinePayment', + 'PlugnPay ' => 'Business::OnlinePayment', + 'PPIPayMover ' => 'Business::OnlinePayment', + 'Protx ' => 'Business::OnlinePayment', + 'PXPost' => 'Business::OnlinePayment', + 'SecureHostingUPG' => 'Business::OnlinePayment', + 'Skipjack' => 'Business::OnlinePayment', + 'StGeorge' => 'Business::OnlinePayment', + 'SurePay' => 'Business::OnlinePayment', + 'TCLink' => 'Business::OnlinePayment', + 'TransactionCentral' => 'Business::OnlinePayment', + 'TransFirsteLink' => 'Business::OnlinePayment', + 'Vanco' => 'Business::OnlinePayment', + 'viaKLIX' => 'Business::OnlinePayment', + 'VirtualNet' => 'Business::OnlinePayment', + 'WesternACH' => 'Business::OnlinePayment', +); + +my @actions = ( + 'Normal Authorization', + 'Authorization Only', + 'Authorization Only, Post Authorization', + ); + +my $fields = [ + { + field => 'gateway_namespace', + type => 'hidden', + curr_value_callback => sub { my($cgi, $object, $fref) = @_; + $modules{$object->gateway_module} + || 'Business::OnlinePayment' + }, + }, + { + field => 'gateway_module', + type => 'select', + options => [ sort { lc($a) cmp lc ($b) } keys %modules ], + onchange => 'setNamespace', + }, + 'gateway_username', + 'gateway_password', + { + field => 'gateway_action', + type => 'select', + options => \@actions, + }, + 'gateway_callback_url', + { + field => 'gateway_options', + type => 'textarea', + curr_value_callback => sub { my($cgi, $object, $fref) = @_; + join("\r", $object->options ); + }, + }, + ]; + +my $field_callback = sub { + my ($cgi, $object, $field_hashref ) = @_; + if ($object->gatewaynum) { + if ( $field_hashref->{field} eq 'gateway_module' ) { + $field_hashref->{type} = 'fixed'; + } + } +}; </%init> diff --git a/httemplate/edit/phone_device.html b/httemplate/edit/phone_device.html new file mode 100644 index 0000000..a1aa166 --- /dev/null +++ b/httemplate/edit/phone_device.html @@ -0,0 +1,37 @@ +<% include( 'elements/edit.html', + 'name' => 'Phone device', + 'table' => 'phone_device', + 'labels' => { + 'devicenum' => 'Device', + 'devicepart' => 'Device type', + 'mac_addr' => 'MAC address', + }, + 'fields' => [ { 'field' => 'devicepart', + 'type' => 'select-table', + 'table' => 'part_device', + 'name_col' => 'devicename', + 'empty_label' =>'Select device type', + #'hashref' =>{ disabled => '' }, + }, + 'mac_addr', + { 'field' => 'svcnum', + 'type' => 'hidden', + }, + ], + 'menubar' => [], #disable viewall + #'viewall_dir' => 'browse', + 'new_callback' => sub { + my( $cgi, $object ) = @_; + $object->svcnum( $cgi->param('svcnum') ); + }, + ) +%> +<%init> + +# :/ needs agent-virt so you can't futz with arbitrary devices + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + + +</%init> diff --git a/httemplate/edit/pkg_category.html b/httemplate/edit/pkg_category.html index fdc8da6..a07dc58 100644 --- a/httemplate/edit/pkg_category.html +++ b/httemplate/edit/pkg_category.html @@ -3,11 +3,13 @@ 'table' => 'pkg_category', 'fields' => [ 'categoryname', + 'weight', { field=>'disabled', type=>'checkbox', value=>'Y', }, ], 'labels' => { 'categorynum' => 'Category number', 'categoryname' => 'Category name', + 'weight' => 'Weight', 'disabled' => 'Disable category', }, 'viewall_dir' => 'browse', diff --git a/httemplate/edit/prepay_credit.cgi b/httemplate/edit/prepay_credit.cgi index 9e1c30b..ed404b7 100644 --- a/httemplate/edit/prepay_credit.cgi +++ b/httemplate/edit/prepay_credit.cgi @@ -97,14 +97,14 @@ tie my %multiplier, 'Tie::IxHash', tie my %bytemultiplier, 'Tie::IxHash', 1 => 'bytes', - 1000 => 'Kbytes', - 1000000 => 'Mbytes', - 1000000000 => 'Gbytes', + 1024 => 'Kbytes', + 1048576 => 'Mbytes', + 1073741824 => 'Gbytes', ; $cgi->param('multiplier', '60') unless $cgi->param('multiplier'); -$cgi->param('upmultiplier', '1000000') unless $cgi->param('upmultiplier'); -$cgi->param('downmultiplier', '1000000') unless $cgi->param('downmultiplier'); -$cgi->param('totalmultiplier','1000000') unless $cgi->param('totalmultiplier'); +$cgi->param('upmultiplier', '1048576') unless $cgi->param('upmultiplier'); +$cgi->param('downmultiplier', '1048576') unless $cgi->param('downmultiplier'); +$cgi->param('totalmultiplier','1048576') unless $cgi->param('totalmultiplier'); </%init> diff --git a/httemplate/edit/process/REAL_cust_pkg.cgi b/httemplate/edit/process/REAL_cust_pkg.cgi index ebcb7e4..d4ba976 100755 --- a/httemplate/edit/process/REAL_cust_pkg.cgi +++ b/httemplate/edit/process/REAL_cust_pkg.cgi @@ -3,16 +3,23 @@ <% $cgi->redirect(popurl(2). "REAL_cust_pkg.cgi?". $cgi->query_string ) %> %} else { % my $custnum = $new->custnum; -<% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum#cust_pkg$pkgnum" ) %> +% my $show = $curuser->default_customer_view =~ /^(jumbo|packages)$/ +% ? '' +% : ';show=packages'; +% my $frag = "cust_pkg$pkgnum"; #hack for IE ignoring real #fragment +<% $cgi->redirect(popurl(3). "view/cust_main.cgi?custnum=$custnum$show;fragment=$frag#$frag" ) %> %} <%init> +my $curuser = $FS::CurrentUser::CurrentUser; + die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Edit customer package dates'); + unless $curuser->access_right('Edit customer package dates'); my $pkgnum = $cgi->param('pkgnum') or die; my $old = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); my %hash = $old->hash; +$hash{'start_date'} = $cgi->param('start_date') ? str2time($cgi->param('start_date')) : ''; $hash{'setup'} = $cgi->param('setup') ? str2time($cgi->param('setup')) : ''; $hash{'bill'} = $cgi->param('bill') ? str2time($cgi->param('bill')) : ''; $hash{'last_bill'} = diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 097d382..f72ca0a 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -19,6 +19,8 @@ my $DEBUG = 0; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Edit customer'); +my $conf = new FS::Conf; + my $error = ''; #unmunge stuff @@ -27,8 +29,7 @@ $cgi->param('tax','') unless defined $cgi->param('tax'); $cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] ); -#my $payby = $cgi->param('payby'); -my $payby = $cgi->param('select'); # XXX key +my $payby = $cgi->param('payby'); my %noauto = ( 'CARD' => 'DCRD', @@ -72,55 +73,83 @@ if ( defined($cgi->param('same')) && $cgi->param('same') eq "Y" ) { ); } -if ( $cgi->param('birthdate') && $cgi->param('birthdate') =~ /^([ 0-9\-\/]{0,10})$/) { - my $conf = new FS::Conf; - my $format = $conf->config('date_format') || "%m/%d/%Y"; - my $parser = DateTime::Format::Strptime->new(pattern => $format, - time_zone => 'floating', - ); - my $dt = $parser->parse_datetime($1); - if ($dt) { - $new->setfield('birthdate', $dt->epoch); - $cgi->param('birthdate', $dt->epoch); - } else { -# $error ||= $cgi->param('birthdate') . " is an invalid birthdate:" . $parser->errmsg; - $error ||= "Invalid birthdate: " . $cgi->param('birthdate') . "."; - $cgi->param('birthdate', ''); +my %usedatetime = ( 'birthdate' => 1 ); + +foreach my $dfield (qw( birthdate signupdate )) { + + if ( $cgi->param($dfield) && $cgi->param($dfield) =~ /^([ 0-9\-\/]{0,10})$/) { + + my $value = $1; + my $parsed = ''; + + if ( exists $usedatetime{$dfield} && $usedatetime{$dfield} ) { + + my $format = $conf->config('date_format') || "%m/%d/%Y"; + my $parser = DateTime::Format::Strptime->new( pattern => $format, + time_zone => 'floating', + ); + my $dt = $parser->parse_datetime($value); + if ( $dt ) { + $parsed = $dt->epoch; + } else { + # $error ||= $cgi->param('birthdate') . " is an invalid birthdate:" . $parser->errmsg; + $error ||= "Invalid $dfield: $value"; + } + + } else { + + $parsed = str2time($value) + or $error ||= "Invalid $dfield: $value"; + + } + + $new->setfield( $dfield, $parsed ); + $cgi->param( $dfield, $parsed ); + } + } $new->setfield('paid', $cgi->param('paid') ) if $cgi->param('paid'); +my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); +my @tax_exempt = grep { $cgi->param("tax_$_") eq 'Y' } @exempt_groups; + #perhaps this stuff should go to cust_main.pm -my $cust_pkg = ''; -my $svc_acct = ''; if ( $new->custnum eq '' ) { + my $cust_pkg = ''; + my $svc; + if ( $cgi->param('pkgpart_svcpart') ) { + my $x = $cgi->param('pkgpart_svcpart'); $x =~ /^(\d+)_(\d+)$/ or die "illegal pkgpart_svcpart $x\n"; my($pkgpart, $svcpart) = ($1, $2); + my $part_pkg = qsearchs('part_pkg', { 'pkgpart' => $pkgpart } ); #false laziness: copied from FS::cust_pkg::order (which should become a #FS::cust_main method) my(%part_pkg); # generate %part_pkg # $part_pkg{$pkgpart} is true iff $custnum may purchase $pkgpart my $agent = qsearchs('agent',{'agentnum'=> $new->agentnum }); - #my($type_pkgs); - #foreach $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) { - # my($pkgpart)=$type_pkgs->pkgpart; - # $part_pkg{$pkgpart}++; - #} - # $pkgpart_href->{PKGPART} is true iff $custnum may purchase $pkgpart - my $pkgpart_href = $agent->pkgpart_hashref; - #eslaf - - # this should wind up in FS::cust_pkg! - $error ||= "Agent ". $new->agentnum. " (type ". $agent->typenum. ") can't ". - "purchase pkgpart ". $pkgpart - #unless $part_pkg{ $pkgpart }; - unless $pkgpart_href->{ $pkgpart }; + + if ( $agent ) { + # $pkgpart_href->{PKGPART} is true iff $custnum may purchase $pkgpart + my $pkgpart_href = $agent->pkgpart_hashref + if $agent; + #eslaf + + # this should wind up in FS::cust_pkg! + $error ||= "Agent ". $new->agentnum. " (type ". $agent->typenum. + ") can't purchase pkgpart ". $pkgpart + #unless $part_pkg{ $pkgpart }; + unless $pkgpart_href->{ $pkgpart } + || $agent->agentnum == $part_pkg->agentnum; + } else { + $error = 'Select agent'; + } $cust_pkg = new FS::cust_pkg ( { #later 'custnum' => $custnum, @@ -132,33 +161,52 @@ if ( $new->custnum eq '' ) { #$error ||= $cust_svc->check; - my %svc_acct = ( - 'svcpart' => $svcpart, - 'username' => $cgi->param('username'), - '_password' => $cgi->param('_password'), - 'popnum' => $cgi->param('popnum'), - ); - $svc_acct{'domsvc'} = $cgi->param('domsvc') - if $cgi->param('domsvc'); + my $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } ); + my $svcdb = $part_svc->svcdb; + + if ( $svcdb eq 'svc_acct' ) { + + my %svc_acct = ( + 'svcpart' => $svcpart, + 'username' => scalar($cgi->param('username')), + '_password' => scalar($cgi->param('_password')), + 'popnum' => scalar($cgi->param('popnum')), + ); + $svc_acct{'domsvc'} = $cgi->param('domsvc') + if $cgi->param('domsvc'); + + $svc = new FS::svc_acct \%svc_acct; + + #and just in case you were silly + $svc->svcpart($svcpart); + $svc->username($cgi->param('username')); + $svc->_password($cgi->param('_password')); + $svc->popnum($cgi->param('popnum')); + + } elsif ( $svcdb eq 'svc_phone' ) { + + my %svc_phone = ( + 'svcpart' => $svcpart, + map { $_ => scalar($cgi->param($_)) } + qw( countrycode phonenum sip_password pin phone_name ) + ); - $svc_acct = new FS::svc_acct \%svc_acct; + $svc = new FS::svc_phone \%svc_phone; - #and just in case you were silly - $svc_acct->svcpart($svcpart); - $svc_acct->username($cgi->param('username')); - $svc_acct->_password($cgi->param('_password')); - $svc_acct->popnum($cgi->param('popnum')); + } else { + die "$svcdb not handled on new customer yet"; + } #$error ||= $svc_acct->check; - } elsif ( $cgi->param('username') ) { #good thing to catch - $error = "Can't assign username without a package!"; } use Tie::RefHash; tie my %hash, 'Tie::RefHash'; - %hash = ( $cust_pkg => [ $svc_acct ] ) if $cust_pkg; - $error ||= $new->insert( \%hash, \@invoicing_list ); + %hash = ( $cust_pkg => [ $svc ] ) if $cust_pkg; + $error ||= $new->insert( \%hash, \@invoicing_list, + 'tax_exemption' => \@tax_exempt, + ); my $conf = new FS::Conf; if ( $conf->exists('backend-realtime') && ! $error ) { @@ -201,7 +249,9 @@ if ( $new->custnum eq '' ) { local($FS::cust_main::DEBUG) = $DEBUG if $DEBUG; local($FS::Record::DEBUG) = $DEBUG if $DEBUG; - $error ||= $new->replace($old, \@invoicing_list); + $error ||= $new->replace( $old, \@invoicing_list, + 'tax_exemption' => \@tax_exempt, + ); warn "$me returned from replace" if $DEBUG; diff --git a/httemplate/edit/process/cust_main_attach.cgi b/httemplate/edit/process/cust_main_attach.cgi new file mode 100644 index 0000000..98f4d09 --- /dev/null +++ b/httemplate/edit/process/cust_main_attach.cgi @@ -0,0 +1,99 @@ +%if ($error) { +% $cgi->param('error', $error); +<% $cgi->redirect(popurl(2). 'cust_main_attach.cgi?'. $cgi->query_string ) %> +%} else { +% my $act = 'added'; +% $act = 'updated' if ($attachnum); +% $act = 'purged' if($attachnum and $purge); +% $act = 'undeleted' if($attachnum and $undelete); +% $act = 'deleted' if($attachnum and $delete); +<% header('Attachment ' . $act ) %> + <SCRIPT TYPE="text/javascript"> + window.top.location.reload(); + </SCRIPT> + </BODY></HTML> +% } +<%init> + +my $error; +$cgi->param('custnum') =~ /^(\d+)$/ + or die "Illegal custnum: ". $cgi->param('custnum'); +my $custnum = $1; + +$cgi->param('attachnum') =~ /^(\d*)$/ + or die "Illegal attachnum: ". $cgi->param('attachnum'); +my $attachnum = $1; + +my $curuser = $FS::CurrentUser::CurrentUser; +my $otaker = $curuser->name; +$otaker = $curuser->username if ($otaker eq "User, Legacy"); + +my $delete = $cgi->param('delete'); +my $undelete = $cgi->param('undelete'); +my $purge = $cgi->param('purge'); + +my $new = new FS::cust_attachment ( { + attachnum => $attachnum, + custnum => $custnum, + _date => time, + otaker => $otaker, + disabled => '', +}); +my $old; + +if($attachnum) { + $old = qsearchs('cust_attachment', { attachnum => $attachnum }); + if(!$old) { + $error = "Attachnum '$attachnum' not found"; + } + elsif($purge) { # do nothing + } + else { + map { $new->$_($old->$_) } + ('_date', 'otaker', 'body', 'disabled'); + $new->filename($cgi->param('filename') || $old->filename); + $new->mime_type($cgi->param('mime_type') || $old->mime_type); + if($delete and not $old->disabled) { + $new->disabled(time); + } + if($undelete and $old->disabled) { + $new->disabled(''); + } + } +} +else { # This is a new attachment, so require a file. + + my $filename = $cgi->param('file'); + if($filename) { + $new->filename($filename); + $new->mime_type($cgi->uploadInfo($filename)->{'Content-Type'}); + + local $/; + my $fh = $cgi->upload('file'); + $new->body(<$fh>); + } + else { + $error = 'No file uploaded'; + } +} +my $action = 'Add'; +$action = 'Edit' if $attachnum; +$action = 'Delete' if $attachnum and $delete; +$action = 'Undelete' if $attachnum and $undelete; +$action = 'Purge' if $attachnum and $purge; + +$error = 'access denied' unless $curuser->access_right($action . ' attachment'); + +if(!$error) { + if($old and $old->disabled and $purge) { + $error = $old->delete; + } + elsif($old) { + $error = $new->replace($old); + } + else { + $error = $new->insert; + } +} + +</%init> diff --git a/httemplate/edit/process/cust_main_county-collapse.cgi b/httemplate/edit/process/cust_main_county-collapse.cgi index a917825..18bd1fd 100755 --- a/httemplate/edit/process/cust_main_county-collapse.cgi +++ b/httemplate/edit/process/cust_main_county-collapse.cgi @@ -1,44 +1,37 @@ -% -% -%my($query) = $cgi->keywords; -%$query =~ /^(\d+)$/ or die "Illegal taxnum!"; -%my $taxnum = $1; -%my $cust_main_county = qsearchs('cust_main_county', { 'taxnum' => $taxnum } ) -% or die "Unknown taxnum $taxnum"; -% -%#really should do this in a .pm & start transaction -% -%foreach my $delete ( qsearch('cust_main_county', { -% 'country' => $cust_main_county->country, -% 'state' => $cust_main_county->state -% } ) ) { -%# unless ( qsearch('cust_main',{ -%# 'state' => $cust_main_county->getfield('state'), -%# 'county' => $cust_main_county->getfield('county'), -%# 'country' => $cust_main_county->getfield('country'), -%# } ) ) { -% my $error = $delete->delete; -% die $error if $error; -%# } else { -% #should really fix the $cust_main record -%# } -% -%} -% -%$cust_main_county->taxnum(''); -%$cust_main_county->county(''); -%my $error = $cust_main_county->insert; -%die $error if $error; -% -%print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi"); -% -% +<% $cgi->redirect(popurl(3). "browse/cust_main_county.cgi") %> <%init> -#this isn't actually linked from anywhere just now, but it will be again soon - die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ or die "Illegal taxnum!"; +my $taxnum = $1; +my $cust_main_county = qsearchs('cust_main_county', { 'taxnum' => $taxnum } ) + or die "Unknown taxnum $taxnum"; + +#really should do this in a .pm & start transaction + +foreach my $delete ( qsearch('cust_main_county', { + 'country' => $cust_main_county->country, + 'state' => $cust_main_county->state + } ) ) { +# unless ( qsearch('cust_main',{ +# 'state' => $cust_main_county->getfield('state'), +# 'county' => $cust_main_county->getfield('county'), +# 'country' => $cust_main_county->getfield('country'), +# } ) ) { + my $error = $delete->delete; + die $error if $error; +# } else { + #should really fix the $cust_main record +# } + +} + +$cust_main_county->taxnum(''); +$cust_main_county->county(''); +my $error = $cust_main_county->insert; +die $error if $error; </%init> diff --git a/httemplate/edit/process/cust_pay.cgi b/httemplate/edit/process/cust_pay.cgi index 647f6fc..a310c53 100755 --- a/httemplate/edit/process/cust_pay.cgi +++ b/httemplate/edit/process/cust_pay.cgi @@ -7,7 +7,7 @@ % if ( $cgi->param('apply') eq 'yes' ) { % my $cust_main = qsearchs('cust_main', { 'custnum' => $linknum }) % or die "unknown custnum $linknum"; -% $cust_main->apply_payments; +% $cust_main->apply_payments( 'manual' => 1 ); % } % if ( $link eq 'popup' ) { % @@ -46,7 +46,9 @@ my $new = new FS::cust_pay ( { _date => $_date, map { $_, scalar($cgi->param($_)); - } qw(paid payby payinfo paybatch) + } qw( paid payby payinfo paybatch + pkgnum + ) #} fields('cust_pay') } ); diff --git a/httemplate/edit/process/cust_tax_adjustment.html b/httemplate/edit/process/cust_tax_adjustment.html new file mode 100644 index 0000000..204b5b9 --- /dev/null +++ b/httemplate/edit/process/cust_tax_adjustment.html @@ -0,0 +1,41 @@ +% if ( $error ) { +% $cgi->param('error', $error ); +<% $cgi->redirect($p.'cust_tax_adjustment.html?'. $cgi->query_string) %> +% } else { +<% header("Tax adjustment added") %> + <SCRIPT TYPE="text/javascript"> + //window.top.location.reload(); + parent.cClick(); + </SCRIPT> + </BODY></HTML> +% } +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Add customer tax adjustment'); + +my $error = ''; +my $conf = new FS::conf; +my $param = $cgi->Vars; + +$param->{"custnum"} =~ /^(\d+)$/ + or $error .= "Illegal customer number " . $param->{"custnum"} . " "; +my $custnum = $1; + +$param->{"amount"} =~ /^\s*(\d*(?:\.?\d{1,2}))\s*$/ + or $error .= "Illegal amount " . $param->{"amount"} . " "; +my $amount = $1; + +unless ( $error ) { + + my $cust_tax_adjustment = new FS::cust_tax_adjustment { + 'custnum' => $custnum, + 'taxname' => $param->{'taxname'}, + 'amount' => $amount, + 'comment' => $param->{'comment'}, + }; + $error = $cust_tax_adjustment->insert; + +} + +</%init> diff --git a/httemplate/edit/process/domreg.cgi b/httemplate/edit/process/domreg.cgi new file mode 100755 index 0000000..a95474e --- /dev/null +++ b/httemplate/edit/process/domreg.cgi @@ -0,0 +1,62 @@ +%if ($error) { +% $cgi->param('error', $error); +% errorpage($error); +%} else { +<% $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum") %> +%} +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +$cgi->param('op') =~ /^(register|transfer|revoke|renew)$/ or die "Illegal operation"; +my $operation = $1; +#my($query) = $cgi->keywords; +#$query =~ /^(\d+)$/; +$cgi->param('svcnum') =~ /^(\d*)$/ or die "Illegal svcnum!"; +my $svcnum = $1; +my $svc_domain = qsearchs({ + 'select' => 'svc_domain.*', + 'table' => 'svc_domain', + 'addl_from' => ' LEFT JOIN cust_svc USING ( svcnum ) '. + ' LEFT JOIN cust_pkg USING ( pkgnum ) '. + ' LEFT JOIN cust_main USING ( custnum ) ', + 'hashref' => {'svcnum'=>$svcnum}, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +}); +die "Unknown svcnum" unless $svc_domain; + +my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum}); +my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } ); +die "Unknown svcpart" unless $part_svc; + +my $error = ''; + +my @exports = $part_svc->part_export(); + +my $registrar; +my $export; + +# Find the first export that does domain registration +foreach (@exports) { + $export = $_ if $_->can('registrar'); +} + +my $period = 1; # Current OpenSRS export can only handle 1 year registrations + +# If we have a domain registration export, get the registrar object +if ($export) { + if ($operation eq 'register') { + $error = $export->register( $svc_domain, $period ); + } elsif ($operation eq 'transfer') { + $error = $export->transfer( $svc_domain ); + } elsif ($operation eq 'revoke') { + $error = $export->revoke( $svc_domain ); + } elsif ($operation eq 'renew') { + $cgi->param('period') =~ /^(\d+)$/ or die "Illegal renewal period!"; + $period = $1; + $error = $export->renew( $svc_domain, $period ); + } +} + +</%init> diff --git a/httemplate/edit/process/elements/ApplicationCommon.html b/httemplate/edit/process/elements/ApplicationCommon.html index 2782dc2..e0c5bd7 100644 --- a/httemplate/edit/process/elements/ApplicationCommon.html +++ b/httemplate/edit/process/elements/ApplicationCommon.html @@ -72,6 +72,6 @@ my $new; #} -my $error = $new->insert; +my $error = $new->insert( 'manual' => 1 ); </%init> diff --git a/httemplate/edit/process/part_device.html b/httemplate/edit/process/part_device.html new file mode 100644 index 0000000..2b7e1da --- /dev/null +++ b/httemplate/edit/process/part_device.html @@ -0,0 +1,11 @@ +<% include( 'elements/process.html', + 'table' => 'part_device', + 'viewall_dir' => 'browse', + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +</%init> diff --git a/httemplate/edit/process/part_export.cgi b/httemplate/edit/process/part_export.cgi index b5f82e8..209419f 100644 --- a/httemplate/edit/process/part_export.cgi +++ b/httemplate/edit/process/part_export.cgi @@ -16,7 +16,8 @@ my $old = qsearchs('part_export', { 'exportnum'=>$exportnum } ) if $exportnum; #fixup options #warn join('-', split(',',$cgi->param('options'))); my %options = map { - my $value = $cgi->param($_); + my @values = $cgi->param($_); + my $value = scalar(@values) > 1 ? join (' ', @values) : $values[0]; $value =~ s/\r\n/\n/g; #browsers? (textarea) $_ => $value; } split(',', $cgi->param('options')); diff --git a/httemplate/edit/process/part_pkg.cgi b/httemplate/edit/process/part_pkg.cgi index 96c5b36..019224c 100755 --- a/httemplate/edit/process/part_pkg.cgi +++ b/httemplate/edit/process/part_pkg.cgi @@ -93,6 +93,7 @@ my $args_callback = sub { } ( $optionname => $value ); } + grep { $_ !~ /^report_option_/ } @options; foreach ( split(',', $cgi->param('taxproductnums') ) ) { @@ -102,6 +103,11 @@ my $args_callback = sub { $options{"usage_taxproductnum_$_"} = $value; } + foreach ( $cgi->param('report_option') ) { + $error ||= "Illegal optional report class: $_" unless ( $_ =~ /^\d*$/ ); + $options{"report_option_$_"} = 1; + } + $options{$_} = scalar( $cgi->param($_) ) for (qw( setup_fee recur_fee )); @@ -134,7 +140,13 @@ my $args_callback = sub { my $redirect_callback = sub { #my( $cgi, $new ) = @_; return '' unless $custnum; - popurl(3). "view/cust_main.cgi?keywords=$custnum;dummy="; + my $show = $curuser->default_customer_view =~ /^(jumbo|packages)$/ + ? '' + : ';show=packages'; + #my $frag = "cust_pkg$pkgnum"; #hack for IE ignoring real #fragment + + #can we link back to the specific customized package? it would be nice... + popurl(3). "view/cust_main.cgi?custnum=$custnum$show;dummy="; }; #these should probably move to @args above and be processed by part_pkg.pm... @@ -152,16 +164,28 @@ my @process_m2m = ( 'target_table' => 'part_pkg', 'base_field' => 'src_pkgpart', 'target_field' => 'dst_pkgpart', - 'hashref' => { 'link_type' => 'bill' }, - 'params' => [ map $cgi->param($_), grep /^bill_dst_pkgpart/, $cgi->param ], - }, - { 'link_table' => 'part_pkg_link', - 'target_table' => 'part_pkg', - 'base_field' => 'src_pkgpart', - 'target_field' => 'dst_pkgpart', - 'hashref' => { 'link_type' => 'svc' }, - 'params' => [ map $cgi->param($_), grep /^svc_dst_pkgpart/, $cgi->param ], + 'hashref' => { 'link_type' => 'svc', 'hidden' => '' }, + 'params' => [ map $cgi->param($_), + grep /^svc_dst_pkgpart/, $cgi->param + ], }, + map { + my $hidden = $_; + { 'link_table' => 'part_pkg_link', + 'target_table' => 'part_pkg', + 'base_field' => 'src_pkgpart', + 'target_field' => 'dst_pkgpart', + 'hashref' => { 'link_type' => 'bill', 'hidden' => $hidden }, + 'params' => [ map { $cgi->param($_) } + grep { my $param = "bill_dst_pkgpart__hidden"; + my $digit = ''; + (($digit) = /^bill_dst_pkgpart(\d+)/ ) && + $cgi->param("$param$digit") eq $hidden; + } + $cgi->param + ], + }, + } ( '', 'Y' ), ); foreach my $override_class ($cgi->param) { diff --git a/httemplate/edit/process/part_pkg_report_option.html b/httemplate/edit/process/part_pkg_report_option.html new file mode 100644 index 0000000..052aabd --- /dev/null +++ b/httemplate/edit/process/part_pkg_report_option.html @@ -0,0 +1,11 @@ +<% include( 'elements/process.html', + 'table' => 'part_pkg_report_option', + 'viewall_dir' => 'browse', + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +</%init> diff --git a/httemplate/edit/process/part_pkg_taxclass.html b/httemplate/edit/process/part_pkg_taxclass.html index 8f149bb..b37279f 100644 --- a/httemplate/edit/process/part_pkg_taxclass.html +++ b/httemplate/edit/process/part_pkg_taxclass.html @@ -1,53 +1,17 @@ -% if ( $error ) { -% $cgi->param('error', $error); -<% $cgi->redirect(popurl(2). "part_pkg_taxclass.html?". $cgi->query_string ) %> -%} else { -<% $cgi->redirect(popurl(3). "browse/cust_main_county.cgi?taxclass=". uri_escape($part_pkg_taxclass->taxclass) ) %> -%} +<% include( 'elements/process.html', + 'table' => 'part_pkg_taxclass', + 'redirect' => sub { + my( $cgi, $part_pkg_taxclass ) = @_; + + popurl(3). 'browse/cust_main_county.cgi?'. + 'taxclass='. uri_escape($part_pkg_taxclass->taxclass). + ';dummy='; + }, + ) +%> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my $part_pkg_taxclass = new FS::part_pkg_taxclass { - 'taxclass' => $cgi->param('taxclass'), -}; - -#maybe this whole thing should be in a transaction. at some point, no biggie -#none of the follow-up stuff will fail unless there's a more serious problem -#than a hanging record in part_pkg_taxclass... - -my $error = $part_pkg_taxclass->insert; - -unless ( $error ) { - #auto-add the new taxclass to any regions that have taxclasses already - - my $sth = dbh->prepare(" - SELECT country, state, county FROM cust_main_county - WHERE taxclass IS NOT NULL AND taxclass != '' - GROUP BY country, state, county - ") or die dbh->errstr; - $sth->execute or die $sth->errstr; - - while ( my $row = $sth->fetchrow_hashref ) { - warn "inserting for $row"; - my $cust_main_county = new FS::cust_main_county { - 'country' => $row->{country}, - 'state' => $row->{state}, - 'county' => $row->{county}, - 'tax' => 0, - 'taxclass' => $part_pkg_taxclass->taxclass, - #exempt_amount - #taxname - #setuptax - #recurtax - }; - $error = $cust_main_county->insert; - #last if $error; - die $error if $error; - } - - -} - </%init> diff --git a/httemplate/edit/process/payment_gateway.html b/httemplate/edit/process/payment_gateway.html index b16bc3d..812c988 100644 --- a/httemplate/edit/process/payment_gateway.html +++ b/httemplate/edit/process/payment_gateway.html @@ -1,35 +1,22 @@ -%if ( $error ) { -% $cgi->param('error', $error); -<% $cgi->redirect(popurl(2). "payment_gateway.html?". $cgi->query_string ) %> -%} else { -<% $cgi->redirect(popurl(3). "browse/payment_gateway.html") %> -%} +<% include( 'elements/process.html', + 'table' => 'payment_gateway', + 'viewall_dir' => 'browse', + 'args_callback' => $args_callback, + ) +%> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my $gatewaynum = $cgi->param('gatewaynum'); +my $args_callback = sub { + my ( $cgi, $new ) = @_; -my $old = qsearchs('payment_gateway',{'gatewaynum'=>$gatewaynum}) if $gatewaynum; + my @options = split(/\r?\n/, $cgi->param('gateway_options') ); + pop @options + if scalar(@options) % 2 && $options[-1] =~ /^\s*$/; + (@options) +}; -my $new = new FS::payment_gateway ( { - map { - $_, scalar($cgi->param($_)); - } fields('payment_gateway') -} ); - -my @options = split(/\r?\n/, $cgi->param('gateway_options') ); -pop @options - if scalar(@options) % 2 && $options[-1] =~ /^\s*$/; -my %options = @options; - -my $error; -if ( $gatewaynum ) { - $error=$new->replace($old, \%options); -} else { - $error=$new->insert(\%options); - $gatewaynum=$new->getfield('gatewaynum'); -} </%init> diff --git a/httemplate/edit/process/phone_device.html b/httemplate/edit/process/phone_device.html new file mode 100644 index 0000000..df9d5e7 --- /dev/null +++ b/httemplate/edit/process/phone_device.html @@ -0,0 +1,18 @@ +<% include( 'elements/process.html', + 'table' => 'phone_device', + 'redirect' => sub { + my( $cgi, $phone_device ) = @_; + popurl(3).'view/svc_phone.cgi?'. + 'svcnum='. $phone_device->svcnum. + ';devicenum='; + }, + ) +%> +<%init> + +# :/ needs agent-virt so you can't futz with arbitrary devices + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +</%init> diff --git a/httemplate/edit/process/quick-charge.cgi b/httemplate/edit/process/quick-charge.cgi index 8fa57dd..827530e 100644 --- a/httemplate/edit/process/quick-charge.cgi +++ b/httemplate/edit/process/quick-charge.cgi @@ -27,7 +27,7 @@ $param->{"custnum"} =~ /^(\d+)$/ or $error .= "Illegal customer number " . $param->{"custnum"} . " "; my $custnum = $1; -$param->{"amount"} =~ /^\s*(\d+(\.\d{1,2})?)\s*$/ +$param->{"amount"} =~ /^\s*(\d*(?:\.?\d{1,2}))\s*$/ or $error .= "Illegal amount " . $param->{"amount"} . " "; my $amount = $1; @@ -55,6 +55,12 @@ unless ( $error ) { $error ||= $cust_main->charge( { 'amount' => $amount, 'quantity' => $quantity, + 'bill_now' => scalar($cgi->param('bill_now')), + 'invoice_terms' => scalar($cgi->param('invoice_terms')), + 'start_date' => ( scalar($cgi->param('start_date')) + ? str2time($cgi->param('start_date')) + : '' + ), 'pkg' => scalar($cgi->param('pkg')), 'setuptax' => scalar($cgi->param('setuptax')), 'taxclass' => scalar($cgi->param('taxclass')), diff --git a/httemplate/edit/process/quick-cust_pkg.cgi b/httemplate/edit/process/quick-cust_pkg.cgi index 9c24743..7a0f082 100644 --- a/httemplate/edit/process/quick-cust_pkg.cgi +++ b/httemplate/edit/process/quick-cust_pkg.cgi @@ -3,12 +3,15 @@ <% $cgi->redirect(popurl(3). 'misc/order_pkg.html?'. $cgi->query_string ) %> %} else { % my $frag = "cust_pkg". $cust_pkg->pkgnum; +% my $show = $curuser->default_customer_view =~ /^(jumbo|packages)$/ +% ? '' +% : ';show=packages'; <% header('Package ordered') %> <SCRIPT TYPE="text/javascript"> // XXX fancy ajax rebuild table at some point, but a page reload will do for now // XXX chop off trailing #target and replace... ? - window.top.location = '<% popurl(3). "view/cust_main.cgi?keywords=$custnum;fragment=$frag#$frag" %>'; + window.top.location = '<% popurl(3). "view/cust_main.cgi?custnum=$custnum$show;fragment=$frag#$frag" %>'; </SCRIPT> @@ -16,8 +19,10 @@ %} <%init> +my $curuser = $FS::CurrentUser::CurrentUser; + die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Order customer package'); + unless $curuser->access_right('Order customer package'); #untaint custnum (probably not necessary, searching for it is escape enough) $cgi->param('custnum') =~ /^(\d+)$/ @@ -44,6 +49,10 @@ my $locationnum = $1; my $cust_pkg = new FS::cust_pkg { 'custnum' => $custnum, 'pkgpart' => $pkgpart, + 'start_date' => ( scalar($cgi->param('start_date')) + ? str2time($cgi->param('start_date')) + : '' + ), 'refnum' => $refnum, 'locationnum' => $locationnum, }; diff --git a/httemplate/edit/process/svc_domain.cgi b/httemplate/edit/process/svc_domain.cgi index 9993a87..59b5180 100755 --- a/httemplate/edit/process/svc_domain.cgi +++ b/httemplate/edit/process/svc_domain.cgi @@ -18,8 +18,8 @@ my $svcnum = $1; my $new = new FS::svc_domain ( { map { $_, scalar($cgi->param($_)); - #} qw(svcnum pkgnum svcpart domain action purpose) - } ( fields('svc_domain'), qw( pkgnum svcpart action purpose ) ) + #} qw(svcnum pkgnum svcpart domain action) + } ( fields('svc_domain'), qw( pkgnum svcpart action ) ) } ); my $error = ''; diff --git a/httemplate/edit/quick-charge.html b/httemplate/edit/quick-charge.html index c18b2bc..c96fa6c 100644 --- a/httemplate/edit/quick-charge.html +++ b/httemplate/edit/quick-charge.html @@ -3,6 +3,11 @@ ) %> +<LINK REL="stylesheet" TYPE="text/css" HREF="<%$fsurl%>elements/calendar-win2k-2.css" TITLE="win2k-2"> +<SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/calendar_stripped.js"></SCRIPT> +<SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/calendar-en.js"></SCRIPT> +<SCRIPT TYPE="text/javascript" SRC="<%$fsurl%>elements/calendar-setup.js"></SCRIPT> + <% include('/elements/error.html') %> <SCRIPT TYPE="text/javascript"> @@ -20,7 +25,7 @@ function validate_quick_charge () { var pkg = document.QuickChargeForm.pkg.value; var pkg_regex = /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]*)$/ ; var amount = document.QuickChargeForm.amount.value; - var amount_regex = /^\s*\$?\s*(\d+(\.\d{1,2})?)\s*$/ ; + var amount_regex = /^\s*\$?\s*(\d*(\.?\d{1,2}))\s*$/ ; var rval = true; if ( ! amount_regex.test(amount) ) { @@ -53,6 +58,23 @@ function validate_quick_charge () { return false; } +function bill_now_changed (what) { + var form = what.form; + if ( what.checked ) { + form.start_date_text.disabled = true; + form.start_date.style.backgroundColor = '#dddddd'; + form.start_date_button.style.display = 'none'; + form.start_date_button_disabled.style.display = ''; + form.invoice_terms.disabled = false; + } else { + form.start_date_text.disabled = false; + form.start_date.style.backgroundColor = '#ffffff'; + form.start_date_button.style.display = ''; + form.start_date_button_disabled.style.display = 'none'; + form.invoice_terms.disabled = true; + } +} + </SCRIPT> <FORM ACTION="process/quick-charge.cgi" NAME="QuickChargeForm" ID="QuickChargeForm" METHOD="POST" onsubmit="document.QuickChargeForm.submit.disabled=true;return validate_quick_charge();"> @@ -79,6 +101,58 @@ function validate_quick_charge () { <% include('/elements/tr-select-pkg_class.html', 'curr_value' => $cgi->param('classnum') ) %> +<TR> + <TD ALIGN="right">Invoice now</TD> + <TD> + <INPUT TYPE = "checkbox" + NAME = "bill_now" + VALUE = "1" + <% $cgi->param('bill_now') ? 'CHECKED' : '' %> + onChange = "bill_now_changed(this);" + > + with terms + <% include('/elements/select-terms.html', + 'curr_value' => scalar($cgi->param('invoice_terms')), + 'empty_value' => $default_terms, + 'disabled' => ( $cgi->param('bill_now') ? 0 : 1 ), + ) + %> + </TD> +</TR> + +%# false laziness w/misc/order_pkg.html +<TR> + <TD ALIGN="right">Charge date </TD> + <TD> + <INPUT TYPE = "text" + NAME = "start_date" + SIZE = 32 + ID = "start_date_text" + VALUE = "<% $start_date %>" + <% $cgi->param('bill_now') ? 'STYLE = "background-color:#dddddd" DISABLED' : '' %> + > + <IMG SRC = "<%$fsurl%>images/calendar.png" + ID = "start_date_button" + TITLE = "Select date" + STYLE = "cursor:pointer<% $cgi->param('bill_now') ? ';display:none' : '' %>" + > + <IMG SRC = "<%$fsurl%>images/calendar-disabled.png" + ID = "start_date_button_disabled" + <% $cgi->param('bill_now') ? '' : 'STYLE="display:none"' %> + > + <FONT SIZE=-1>(leave blank to charge immediately)</FONT> + </TD> +</TR> + +<SCRIPT TYPE="text/javascript"> + Calendar.setup({ + inputField: "start_date_text", + ifFormat: "%m/%d/%Y", + button: "start_date_button", + align: "BR" + }); +</SCRIPT> + <TR> <TD ALIGN="right">Tax exempt </TD> @@ -179,6 +253,11 @@ my $conf = new FS::Conf; $cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; my $custnum = $1; +my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); #XXX agent-virt + +my $format = "%m/%d/%Y %T %z (%Z)"; #false laziness w/REAL_cust_pkg.cgi? +my $start_date = $cust_main->next_bill_date; +$start_date = $start_date ? time2str($format, $start_date) : ''; my $amount = ''; if ( $cgi->param('amount') =~ /^\s*\$?\s*(\d+(\.\d{1,2})?)\s*$/ ) { @@ -194,4 +273,14 @@ $cgi->param('pkg') =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=\[\]]*)$/ or die 'illegal description'; my $pkg = $1; +my $default_terms; +if ( $cust_main->invoice_terms ) { + $default_terms = 'Customer default ('. $cust_main->invoice_terms. ')'; +} else { + $default_terms = + 'Default ('. + ($conf->config('invoice_default_terms') || 'Payable upon receipt'). + ')'; +} + </%init> diff --git a/httemplate/edit/reg_code.cgi b/httemplate/edit/reg_code.cgi index e57ac09..76790ab 100644 --- a/httemplate/edit/reg_code.cgi +++ b/httemplate/edit/reg_code.cgi @@ -18,7 +18,7 @@ registration codes for <B><% $agent->agent %></B> allowing the following package % my $pkgpart = $part_pkg->pkgpart; <INPUT TYPE="checkbox" NAME="pkgpart<% $pkgpart %>" <% $cgi->param("pkgpart$pkgpart") ? 'CHECKED' : '' %>> - <% $part_pkg->pkg %> - <% $part_pkg->comment %> + <% $part_pkg->pkg_comment %> <BR> % } diff --git a/httemplate/edit/router.cgi b/httemplate/edit/router.cgi index 19e63b3..70eaa45 100755 --- a/httemplate/edit/router.cgi +++ b/httemplate/edit/router.cgi @@ -10,10 +10,12 @@ 'fields' => [ { 'field'=>'routername', 'type'=>'text', 'size'=>32 }, { 'field'=>'agentnum', 'type'=>'select-agent' }, + { 'field'=>'svcnum', 'type'=>'hidden' }, ], 'error_callback' => $callback, 'edit_callback' => $callback, 'new_callback' => $callback, + 'html_table_bottom' => $html_table_bottom, ) %> <%init> @@ -41,4 +43,12 @@ my $callback = sub { } }; +my $html_table_bottom = sub { + my $router = shift; + my $html = ''; + foreach my $field ($router->virtual_fields) { + $html .= $router->pvf($field)->widget('HTML', 'edit', $router->get($field)); + } + $html; +}; </%init> diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi index 58283ef..b9a587d 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -168,7 +168,7 @@ Service # <% $svcnum ? "<B>$svcnum</B>" : " (NEW)" %><BR> <TR> - <TD ALIGN="right">GECOS</TD> + <TD ALIGN="right">Real Name</TD> <TD> <INPUT TYPE="text" NAME="finger" VALUE="<% $svc_acct->finger %>"> </TD> diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi index e60c76c..8a108f8 100644 --- a/httemplate/edit/svc_broadband.cgi +++ b/httemplate/edit/svc_broadband.cgi @@ -2,7 +2,7 @@ 'post_url' => popurl(1). 'process/svc_broadband.cgi', 'name' => 'broadband service', 'table' => 'svc_broadband', - 'labels' => { 'svcnum' => 'Service #', + 'labels' => { 'svcnum' => 'Service', 'description' => 'Description', 'ip_addr' => 'IP address', 'speed_down' => 'Download speed', @@ -14,6 +14,7 @@ 'longitude' => 'Longitude', 'altitude' => 'Altitude', 'vlan_profile' => 'VLAN profile', + 'performance_profile' => 'Performance profile', 'authkey' => 'Authentication key', }, 'fields' => \@fields, @@ -34,7 +35,7 @@ my $conf = new FS::Conf; my @fields = ( qw( description ip_addr speed_down speed_up blocknum ), { field=>'block_label', type=>'fixed' }, - qw( mac_addr latitude longitude altitude vlan_profile authkey ) + qw( mac_addr latitude longitude altitude vlan_profile performance_profile authkey ) ); my $fixedblock = ''; diff --git a/httemplate/edit/svc_domain.cgi b/httemplate/edit/svc_domain.cgi index 56ba604..10079ce 100755 --- a/httemplate/edit/svc_domain.cgi +++ b/httemplate/edit/svc_domain.cgi @@ -7,17 +7,31 @@ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> <INPUT TYPE="hidden" NAME="svcpart" VALUE="<% $svcpart %>"> -<INPUT TYPE="radio" NAME="action" VALUE="N"<% $kludge_action eq 'N' ? ' CHECKED' : '' %>>New +<% ntable("#cccccc",2) %> +<TR> +<P>Domain <INPUT TYPE="text" NAME="domain" VALUE="<% $domain %>" SIZE=28 MAXLENGTH=63> <BR> +% if ($export) { +Available top-level domains: <% $export->option('tlds') %> +</TR> -<INPUT TYPE="radio" NAME="action" VALUE="M"<% $kludge_action eq 'M' ? ' CHECKED' : '' %>>Transfer +<TR> +<INPUT TYPE="radio" NAME="action" VALUE="N"<% $kludge_action eq 'N' ? ' CHECKED' : '' %>>Register at <% $registrar->{'name'} %> +<BR> -<P>Domain <INPUT TYPE="text" NAME="domain" VALUE="<% $domain %>" SIZE=28 MAXLENGTH=63> +<INPUT TYPE="radio" NAME="action" VALUE="M"<% $kludge_action eq 'M' ? ' CHECKED' : '' %>>Transfer to <% $registrar->{'name'} %> +<BR> -<BR>Purpose/Description: <INPUT TYPE="text" NAME="purpose" VALUE="<% $purpose %>" SIZE=64> +<INPUT TYPE="radio" NAME="action" VALUE="I"<% $kludge_action eq 'I' ? ' CHECKED' : '' %>>Registered elsewhere -<P><INPUT TYPE="submit" VALUE="Submit"> +</TR> + +% } +<TR> +<P><INPUT TYPE="submit" VALUE="Submit"> +</TR> +</TABLE> </FORM> <% include('/elements/footer.html') %> @@ -27,7 +41,7 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? -my($svcnum, $pkgnum, $svcpart, $kludge_action, $purpose, $part_svc, +my($svcnum, $pkgnum, $svcpart, $kludge_action, $part_svc, $svc_domain); if ( $cgi->param('error') ) { @@ -38,7 +52,6 @@ if ( $cgi->param('error') ) { $pkgnum = $cgi->param('pkgnum'); $svcpart = $cgi->param('svcpart'); $kludge_action = $cgi->param('action'); - $purpose = $cgi->param('purpose'); $part_svc = qsearchs('part_svc', { 'svcpart' => $svcpart } ); die "No part_svc entry!" unless $part_svc; @@ -61,7 +74,6 @@ if ( $cgi->param('error') ) { } else { #editing $kludge_action = ''; - $purpose = ''; my($query) = $cgi->keywords; $query =~ /^(\d+)$/ or die "unparsable svcnum"; $svcnum=$1; @@ -82,6 +94,20 @@ my $action = $svcnum ? 'Edit' : 'Add'; my $svc = $part_svc->getfield('svc'); +my @exports = $part_svc->part_export(); + +my $registrar; +my $export; + +# Find the first export that does domain registration +foreach (@exports) { + $export = $_ if $_->can('registrar'); +} +# If we have a domain registration export, get the registrar object +if ($export) { + $registrar = $export->registrar; +} + my $otaker = getotaker; my $domain = $svc_domain->domain; diff --git a/httemplate/edit/svc_www.cgi b/httemplate/edit/svc_www.cgi index eeb6f67..cd4db75 100644 --- a/httemplate/edit/svc_www.cgi +++ b/httemplate/edit/svc_www.cgi @@ -38,7 +38,7 @@ Service #<B><% $svcnum ? $svcnum : "(NEW)" %></B> % foreach $_ (keys %svc_acct) { <OPTION<% ($_ eq $usersvc) ? " SELECTED" : "" %> VALUE="<%$_%>"><% $svc_acct{$_} %> % } - <SELECT> + </SELECT> </TD> </TR> % } |