diff options
Diffstat (limited to 'httemplate/edit')
42 files changed, 1215 insertions, 718 deletions
diff --git a/httemplate/edit/REAL_cust_pkg.cgi b/httemplate/edit/REAL_cust_pkg.cgi index 166a3b7ea..99e911ae5 100755 --- a/httemplate/edit/REAL_cust_pkg.cgi +++ b/httemplate/edit/REAL_cust_pkg.cgi @@ -9,6 +9,29 @@ <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT> <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT> +<SCRIPT TYPE="text/javascript"> +var submit_fields = []; +function confirm_changes() { + var i; + var querystring = 'pkgnum=<%$pkgnum%>'; + var f = document.forms.formname; + for(i = 0; i < submit_fields.length; i++) { + querystring += ';' + + submit_fields[i] + + '=' + + encodeURIComponent(f.elements[submit_fields[i] + '_text'].value); + } + overlib( + OLiframeContent( + '<%$p%>/misc/confirm-cust_pkg-edit_dates.html?' + querystring, + 576, 576, 'confirm_popup' + ), + CAPTION, 'Package date changes', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', + MIDX, 0, MIDY, 0, DRAGGABLE, BGCOLOR, '#333399', CGCOLOR, '#333399', + TEXTSIZE, 3 + ); +} +</SCRIPT> <FORM NAME="formname" ACTION="process/REAL_cust_pkg.cgi" METHOD="POST"> <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> @@ -31,6 +54,15 @@ <TD BGCOLOR="#ffffff"><% $part_pkg->pkg %></TD> </TR> +% if ( $cust_pkg->main_pkgnum ) { +% my $main_pkg = $cust_pkg->main_pkg; + <TR> + <TD ALIGN="right">Supplemental to</TD> + <TD BGCOLOR="#ffffff">Package #<% $cust_pkg->main_pkgnum%>: \ + <% $main_pkg->part_pkg->pkg %></TD> + </TR> + +% } <TR> <TD ALIGN="right">Custom</TD> <TD BGCOLOR="#ffffff"><% $part_pkg->custom %></TD> @@ -38,7 +70,7 @@ <TR> <TD ALIGN="right">Comment</TD> - <TD BGCOLOR="#ffffff"><% $part_pkg->comment %></TD> + <TD BGCOLOR="#ffffff"><% $part_pkg->comment |h %></TD> </TR> <TR> @@ -50,14 +82,14 @@ % if ( $cust_pkg->setup && ! $cust_pkg->start_date ) { <& .row_display, cust_pkg=>$cust_pkg, column=>'start_date', label=>'Start' &> % } else { - <& .row_edit, cust_pkg=>$cust_pkg, column=>'start_date', label=>'Start' &> + <& .row_edit, cust_pkg=>$cust_pkg, column=>'start_date', label=>'Start', if_primary=>1 &> % } - <& .row_edit, cust_pkg=>$cust_pkg, column=>'setup', label=>'Setup' &> + <& .row_edit, cust_pkg=>$cust_pkg, column=>'setup', label=>'Setup', if_primary=>1 &> <& .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 &> %#if ( $cust_pkg->contract_end or $part_pkg->option('contract_end_months',1) ) { - <& .row_edit, cust_pkg=>$cust_pkg, column=>'contract_end',label=>'Contract end' &> + <& .row_edit, cust_pkg=>$cust_pkg, column=>'contract_end',label=>'Contract end', if_primary=>1 &> %#} <& .row_display, cust_pkg=>$cust_pkg, column=>'adjourn', label=>'Adjournment', note=>'(will <b>suspend</b> this package when the date is reached)' &> <& .row_display, cust_pkg=>$cust_pkg, column=>'susp', label=>'Suspension' &> @@ -73,10 +105,17 @@ $column $label $note => '' + $if_primary => 0 </%args> % my $value = $cust_pkg->get($column); % $value = $value ? time2str($format, $value) : ""; - +% +% # if_primary for the dates that can't be edited on supplemental packages +% if ($if_primary and $cust_pkg->main_pkgnum) { + <INPUT TYPE="hidden" ID="<%$column%>_text" VALUE="<% $cust_pkg->get($column) %>"> + <SCRIPT>submit_fields.push('<%$column%>');</SCRIPT> + <& .row_display, %ARGS &> +% } else { <TR> <TD ALIGN="right"><% $label %> date</TD> <TD> @@ -104,8 +143,11 @@ button: "<% $column %>_button", align: "BR" }); - </SCRIPT> + submit_fields.push('<%$column%>'); + + </SCRIPT> +% } </%def> <%def .row_display> @@ -114,6 +156,7 @@ $column $label $note => '' + $is_primary => 0 #ignored </%args> % if ( $cust_pkg->get($column) ) { <TR> @@ -130,7 +173,7 @@ </TABLE> <BR> -<INPUT TYPE="submit" VALUE="<% mt('Apply changes') |h %>"> +<INPUT TYPE="button" VALUE="<% mt('Apply changes') |h %>" onclick="confirm_changes()"> </FORM> <% include('/elements/footer.html') %> @@ -160,38 +203,6 @@ if ( $cgi->param('error') ) { my @errors = (); my %errors = map { $_=>1 } split(',', $cgi->param('error')); $cgi->param('error', ''); - - if ( $errors{'_bill_areyousure'} ) { - if ( $cgi->param('bill') =~ /^([\s\d\/\:\-\(\w\)]*)$/ ) { - my $bill = $1; - push @errors, - "You are attempting to set the next bill date to $bill, which is - in the past. This will charge the customer for the interval - from $bill until now. Are you sure you want to do this? ". - '<INPUT TYPE="checkbox" NAME="bill_areyousure" VALUE="1">'; - } - } - - if ( $errors{'_setup_areyousure'} ) { - push @errors, - "You are attempting to remove the setup date. This will re-charge the - customer for the setup fee. Are you sure you want to do this? ". - '<INPUT TYPE="checkbox" NAME="setup_areyousure" VALUE="1">'; - } - - if ( $errors{'_setupadd_areyousure'} ) { - push @errors, - "You are attempting to add a setup date. This will prevent charging the - customer for the setup fee. Are you sure you want to do this? ". - '<INPUT TYPE="checkbox" NAME="setupadd_areyousure" VALUE="1">'; - } - - if ( $errors{'_start'} ) { - push @errors, - "You are attempting to add a start date to a package that has already - started billing."; - } - $error = join('<BR><BR>', @errors ); } diff --git a/httemplate/edit/bulk-part_pkg.html b/httemplate/edit/bulk-part_pkg.html new file mode 100644 index 000000000..a1c6f0c9b --- /dev/null +++ b/httemplate/edit/bulk-part_pkg.html @@ -0,0 +1,74 @@ +<& /elements/header.html, 'Edit package report classes' &> +%# change that title if we add any other editing controls + +%# this should be centralized somewhere +<STYLE TYPE="text/css"> +.row0 { background-color: #eeeeee; } +.row1 { background-color: #ffffff; } +</STYLE> + +<FORM ACTION="process/bulk-part_pkg.html" METHOD="POST"> +<DIV> +The following packages will be changed:<BR> +% foreach my $pkgpart (sort keys(%part_pkg)) { +<INPUT TYPE="hidden" NAME="pkgpart" VALUE="<% $pkgpart %>"> +<% $part_pkg{$pkgpart}->pkg_comment |h %><BR> +% } +</DIV> +<BR> +<& /elements/table-grid.html &>\ +<& /elements/tr-justtitle.html, value => mt('Report classes') &> +% my $row = 0; +% foreach my $num (sort keys %report_class) { + <TR CLASS="row<%$row % 2%>"> + <TD> +% if ( defined $initial_state{$num} ) { + <& /elements/checkbox.html, + field => 'report_option_'.$num, + value => 1, + curr_value => $initial_state{$num} + &> +% } else { +% # needs to be a tristate so that you can say "don't change it" + <& /elements/checkbox-tristate.html, field => 'report_option_'.$num &> +% } + </TD> + <TD><% $report_class{$num}->name %></TD> + </TR> +% $row++; +% } +</TABLE> +<BR> +<INPUT TYPE="submit"> +</FORM> +<& /elements/footer.html &> +<%init> +die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Bulk edit package definitions'); +my @pkgparts = $cgi->param('pkgpart') + or die "no package definitions selected"; + +my %part_pkg = map { $_ => FS::part_pkg->by_key($_) } @pkgparts; +my %part_pkg_option = map { $_ => { $part_pkg{$_}->options } } @pkgparts; +my %report_class = map { $_->num => $_ } + qsearch('part_pkg_report_option', { disabled => '' }); + +my %initial_state; +foreach my $num (keys %report_class) { + my $yes = 0; + my $no = 0; + foreach my $option (values %part_pkg_option) { + if ( $option->{"report_option_$num"} ) { + $yes = 1; + } else { + $no = 1; + } + } + if ( $yes and $no ) { + $initial_state{$num} = undef; + } elsif ( $yes ) { + $initial_state{$num} = 1; + } elsif ( $no ) { + $initial_state{$num} = 0; + } # else, uh, you didn't provide any pkgparts +} +</%init> diff --git a/httemplate/edit/credit-cust_bill_pkg.html b/httemplate/edit/credit-cust_bill_pkg.html index 3d1cf2438..a5ecb69e3 100644 --- a/httemplate/edit/credit-cust_bill_pkg.html +++ b/httemplate/edit/credit-cust_bill_pkg.html @@ -70,10 +70,11 @@ <TH ALIGN="right" COLSPAN=2>Total credit amount: </TD> <TH ALIGN="right" ID="total_td"><% $money_char %><% sprintf('%.2f', 0) %></TD> </TR> -<INPUT TYPE="hidden" NAME="amount" ID="total_el" VALUE="0.00"> </table> +<INPUT TYPE="hidden" NAME="amount" ID="total_el" VALUE="0.00"> + <table> <& /elements/tr-select-reason.html, @@ -244,7 +245,7 @@ function calc_total(what) { <%init> my $curuser = $FS::CurrentUser::CurrentUser; -die "access denied" unless $curuser->access_right('Post credit'); +die "access denied" unless $curuser->access_right('Credit line items'); #a tiny bit of false laziness w/search/cust_bill_pkg.cgi, but we're pretty # specialized and a piece of UI, not a report diff --git a/httemplate/edit/cust_location.cgi b/httemplate/edit/cust_location.cgi index 80b27c2b3..b90ba66b8 100755 --- a/httemplate/edit/cust_location.cgi +++ b/httemplate/edit/cust_location.cgi @@ -7,20 +7,32 @@ ACTION="<% $p %>edit/process/cust_location.cgi" METHOD=POST> <INPUT TYPE="hidden" NAME="locationnum" VALUE="<% $locationnum %>"> <% ntable('#cccccc') %> -<% include('/elements/location.html', - 'object' => $cust_location, - 'no_asterisks' => 1, - ) %> +<& /elements/location.html, + 'object' => $cust_location, + 'no_asterisks' => 1, + # these are service locations, so they need all this stuff + 'enable_coords' => 1, + 'enable_district' => 1, + 'enable_censustract' => 1, +&> +<& /elements/standardize_locations.html, + 'form' => 'EditLocationForm', + 'callback' => 'document.EditLocationForm.submit();', +&> </TABLE> <BR> <SCRIPT TYPE="text/javascript"> -function areyousure() { - return confirm('Modify this service location?'); +function go() { +% if ( FS::Conf->new->config('address_standardize_method') ) { + standardize_locations(); +% } else { + confirm('Modify this service location?') && + document.EditLocationForm.submit(); +% } } </SCRIPT> -<INPUT TYPE="submit" VALUE="Submit" onclick="return areyousure()"> - +<INPUT TYPE="button" NAME="submitButton" VALUE="Submit" onclick="go()"> </FORM> </BODY> </HTML> diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index be00213e2..2908848c6 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -48,7 +48,7 @@ <TD STYLE="width:650px"> %#; padding-right:2px; vertical-align:top"> <FONT CLASS="fsinnerbox-title"><% mt('Billing address') |h %></FONT> - <TABLE CLASS="fsinnerbox"> + <TABLE CLASS="fsinnerbox" WIDTH="100%"> <& cust_main/before_bill_location.html, $cust_main &> <& /elements/location.html, object => $cust_main->bill_location, @@ -62,7 +62,6 @@ <TR><TD STYLE="height:40px"></TD></TR> <TR> <TD STYLE="width:650px"> -%#; padding-left:2px; vertical-align:top"> <FONT CLASS="fsinnerbox-title"><% mt('Service address') |h %></FONT> <INPUT TYPE="checkbox" NAME="same" @@ -72,19 +71,17 @@ VALUE="Y" <% $has_ship_address ? '' : 'CHECKED' %> ><% mt('same as billing address') |h %> - <TABLE CLASS="fsinnerbox" ID="table_ship_location"> - <& /elements/location.html, - object => $cust_main->ship_location, - prefix => 'ship_', - enable_censustract => 1, - enable_district => 1, - enable_coords => 1, - &> - </TABLE> - <TABLE CLASS="fsinnerbox" ID="table_ship_location_blank" - STYLE="display:none"> - <TR><TD></TD></TR> - </TABLE> + <DIV CLASS="fsinnerbox"> + <TABLE ID="table_ship_location" WIDTH="100%"> + <& /elements/location.html, + object => $cust_main->ship_location, + prefix => 'ship_', + enable_censustract => 1, + enable_district => 1, + enable_coords => 1, + &> + </TABLE> + </DIV> </TD> </TR></TABLE> @@ -94,19 +91,14 @@ function samechanged(what) { %# document.getElementById('table_ship_location').style.visibility = %# what.checked ? 'hidden' : 'visible'; var t1 = document.getElementById('table_ship_location'); - var t2 = document.getElementById('table_ship_location_blank'); if ( what.checked ) { - t2.style.width = t1.clientWidth + 'px'; - t2.style.height = t1.clientHeight + 'px'; - t1.style.display = 'none'; - t2.style.display = ''; + t1.style.visibility = 'hidden'; } else { - t2.style.display = 'none'; - t1.style.display = ''; + t1.style.visibility = 'visible' } } -samechanged(document.getElementById('same')); +//samechanged(document.getElementById('same')); </SCRIPT> <BR> @@ -285,7 +277,8 @@ if ( $cgi->param('error') ) { my( $query ) = $cgi->keywords; $query =~ /^(\d+)$/; $custnum=$1; - $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); + $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die "custnum $custnum not found"; if ( $cust_main->dbdef_table->column('paycvv') && length($cust_main->paycvv) ) { my $paycvv = $cust_main->paycvv; diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index 2925ca87c..5a66f0a60 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -444,10 +444,11 @@ <TR><TD> </TD></TR> +% my $curuser = $FS::CurrentUser::CurrentUser; % my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); - % if ( $conf->exists('cust_class-tax_exempt') % || $conf->exists('tax-cust_exempt-groups-require_individual_nums') +% || ! $curuser->access_right('Edit customer tax exemptions') % ) % { @@ -461,14 +462,16 @@ % } -% foreach my $exempt_group ( @exempt_groups ) { -% my $cust_main_exemption = $cust_main->tax_exemption($exempt_group); -% #escape $exempt_group for NAME etc. -% my $checked = ($cust_main_exemption || $cgi->param("tax_$exempt_group")); - <TR> - <TD> <INPUT TYPE="checkbox" NAME="tax_<% $exempt_group %>" ID="tax_<% $exempt_group %>" VALUE="Y" <% $checked ? 'CHECKED' : '' %> onChange="tax_changed(this)"> Tax Exempt (<% $exempt_group %> taxes)</TD> - <TD> - Exemption number <INPUT TYPE="text" NAME="tax_<% $exempt_group %>_num" ID="tax_<% $exempt_group %>_num" VALUE="<% $cgi->param("tax_$exempt_group".'_num') || ( $cust_main_exemption ? $cust_main_exemption->exempt_number : '' ) |h %>" <% $checked ? '' : 'DISABLED' %>></TD> - </TR> +% if ( $curuser->access_right('Edit customer tax exemptions') ) { +% foreach my $exempt_group ( @exempt_groups ) { +% my $cust_main_exemption = $cust_main->tax_exemption($exempt_group); +% #escape $exempt_group for NAME etc. +% my $checked = ($cust_main_exemption || $cgi->param("tax_$exempt_group")); + <TR> + <TD> <INPUT TYPE="checkbox" NAME="tax_<% $exempt_group %>" ID="tax_<% $exempt_group %>" VALUE="Y" <% $checked ? 'CHECKED' : '' %> onChange="tax_changed(this)"> Tax Exempt (<% $exempt_group %> taxes)</TD> + <TD> - Exemption number <INPUT TYPE="text" NAME="tax_<% $exempt_group %>_num" ID="tax_<% $exempt_group %>_num" VALUE="<% $cgi->param("tax_$exempt_group".'_num') || ( $cust_main_exemption ? $cust_main_exemption->exempt_number : '' ) |h %>" <% $checked ? '' : 'DISABLED' %>></TD> + </TR> +% } % } % unless ( $conf->exists('emailinvoiceonly') ) { @@ -518,7 +521,13 @@ <% $conf->exists('cust_main-require_invoicing_list_email', $agentnum) ? $r : '' %>Email address(es) </TD> - <TD WIDTH="408"><INPUT TYPE="text" NAME="invoicing_list" VALUE="<% join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ) %>"></TD> + <TD WIDTH="408"><INPUT TYPE="text" NAME="invoicing_list" VALUE="<% join(', ', grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ) %>"> + <INPUT TYPE="checkbox" NAME="message_noemail" VALUE="Y" <% + ( $cust_main->message_noemail eq 'Y' ) + ? 'CHECKED' + : '' + %>> <% emt('Do not send notices') %> + </TD> </TR> % } diff --git a/httemplate/edit/cust_main/bottomfixup.js b/httemplate/edit/cust_main/bottomfixup.js index 1cfa52d8f..0de6d9dab 100644 --- a/httemplate/edit/cust_main/bottomfixup.js +++ b/httemplate/edit/cust_main/bottomfixup.js @@ -70,8 +70,8 @@ function copy_payby_fields() { <& /elements/standardize_locations.js, 'callback' => 'submit_continue();', - 'main_prefix' => 'bill_', - 'no_company' => 1, + 'billship' => 1, + 'with_census' => 1, # no with_firm, apparently &> function copyelement(from, to) { diff --git a/httemplate/edit/cust_main/choose_tax_location.html b/httemplate/edit/cust_main/choose_tax_location.html deleted file mode 100644 index ac475c54b..000000000 --- a/httemplate/edit/cust_main/choose_tax_location.html +++ /dev/null @@ -1,87 +0,0 @@ -<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 %>"> -% foreach my $location (@cust_tax_location) { -% my %value = ( zip => $zip5, -% map { $_ => $location->$_ } -% qw ( city state geocode ) -% ); -% map { $value{$_} = $location{$_} } qw ( city state ) -% if $location{country} eq 'CA'; -% -% my $value = encode_entities(objToJson({ %value }) -% ); -% my $content = ''; -% $content .= $location->$_. ' ' x ( $max{$_} - length($location->$_) ) -% foreach qw( city county state ); -% $content .= $location->cityflag eq 'I' ? 'Y' : 'N' ; -% my $selected = '' ; -% if ($geocode && $location->geocode eq $geocode) { -% $selected = 'SELECTED'; -% } - <OPTION VALUE="<% $value %>" STYLE="<% $style %>" <% $selected %>><% $content %> -% } -</SELECT><BR><BR> - -<TABLE><TR> - <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> - -</CENTER> -</FORM> -<%init> - -my $conf = new FS::Conf; - -my %location = (); - -($location{data_vendor}) = $cgi->param('data_vendor') =~ /^([-\w]+)$/; -($location{city}) = $cgi->param('city') =~ /^([\w ]+)$/; -($location{state}) = $cgi->param('state') =~ /^(\w+)$/; -($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 -my $hashref = { 'data_vendor' => $location{data_vendor} }; -$hashref->{zip} = $location{country} eq 'CA' ? substr($zip5,0,1) : $zip5, - -my @keys = keys(%$hashref); -my @cust_tax_location = (); -until ( @cust_tax_location ) { - @cust_tax_location = qsearch({ table => 'cust_tax_location', - hashref => $hashref, - order_by => 'LIMIT 50', - }); - last unless scalar(@keys); - delete $hashref->{ shift @keys }; -} - -my %max = ( city => 4, county => 6, state => 5); -foreach my $location (@cust_tax_location) { - foreach ( qw( city county state ) ) { - my $length = length($location->$_); - $max{$_} = ($length > $max{$_}) ? $length : $max{$_}; - } -} -foreach ( qw( city county state ) ) { - $max{$_} = $location{$_} if $location{$_} > $max{$_}; - $max{$_}++; -} - -my $header = ' '; -$header .= $_. ' ' x ( $max{lc($_)} - length($_) ) - foreach qw( City County State ); -$header .= "In city?"; - -my $style = "font-family:monospace;"; - -</%init> diff --git a/httemplate/edit/cust_main/top_misc.html b/httemplate/edit/cust_main/top_misc.html index cfed8e4f6..b7e86ba78 100644 --- a/httemplate/edit/cust_main/top_misc.html +++ b/httemplate/edit/cust_main/top_misc.html @@ -32,6 +32,44 @@ document.getElementById('contacts_div').style.display = 'none'; } } + + var ship_locked_agents = <% encode_json(\%ship_locked_agents) %>; + var ship_fields = ['address1', 'city', 'state', 'zip', 'country', + 'latitude', 'longitude', 'district']; + function agent_changed(what) { + var agentnum = what.value; + var f = what.form; + if ( ship_locked_agents[agentnum] ) { +% # For this agent, the service location (except address2) +% # should be locked to the agent's location. +% # Set the ship_ fields to those values (just for display) and +% # then disable them. + for(var x in ship_locked_agents[agentnum]) { + f['ship_'+x].value = ship_locked_agents[agentnum][x]; + f['ship_'+x].disabled = true; + } + f['same'].checked = false; + f['same'].disabled = true; + } else { +% # Unlock the ship_ location fields. If they were previously +% # disabled, then they contain some agent's address, which is +% # no longer meaningful. So set them back to the customer's +% # current location. + for(var i=0; i<ship_fields.length; i++) { + x = ship_fields[i]; + if ( f['ship_'+x].disabled ) { + f['ship_'+x].value = f['old_ship_'+x].value; + } + f['ship_'+x].disabled = false; + } + f['same'].disabled = false; + } + samechanged(f['same']); + } + window.onload = function() { + agent_changed(document.getElementById('agentnum')); + } + </SCRIPT> % foreach my $field ($cust_main->virtual_fields) { @@ -51,12 +89,13 @@ % $cust_main->agentnum($agentnum); <INPUT TYPE="hidden" NAME="lock_agentnum" VALUE="<% $agentnum %>"> - <INPUT TYPE="hidden" NAME="agentnum" VALUE="<% $agentnum %>"> + <INPUT TYPE="hidden" NAME="agentnum" ID="agentnum" + VALUE="<% $agentnum %>"> <TR> <TD ALIGN="right"><% mt('Agent') |h %></TD> <TD CLASS="fsdisabled"><% $cust_main->agent->agent |h %></TD> </TR> - + % } else { <& /elements/tr-select-agent.html, @@ -65,6 +104,7 @@ 'empty_label' => emt('Select agent'), 'disable_empty' => ( $cust_main->agentnum ? 1 : 0 ), 'viewall_right' => emt('None'), + 'onchange' => 'agent_changed(this)', &> % } @@ -201,4 +241,17 @@ my $curuser = $FS::CurrentUser::CurrentUser; my $r = qq!<font color="#ff0000">*</font> !; +# which agents lock the service address, if any +my %ship_locked_agents; +foreach (qsearch('agent',{})) { + my $agentnum = $_->agentnum; + next unless $conf->exists('agent-ship_address', $_->agentnum); + my $cust_main = $_->agent_cust_main or next; + my $agent_ship_location = $cust_main->ship_location; + $ship_locked_agents{$agentnum} = +{ + map { $_ => $agent_ship_location->$_ } + qw(address1 city state zip country latitude longitude district) + }; +} + </%init> diff --git a/httemplate/edit/cust_pkg.cgi b/httemplate/edit/cust_pkg.cgi index dd1ed335f..88e925460 100755 --- a/httemplate/edit/cust_pkg.cgi +++ b/httemplate/edit/cust_pkg.cgi @@ -7,7 +7,6 @@ <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> %#current packages -%my @cust_pkg = qsearch('cust_pkg', { 'custnum' => $custnum, 'cancel' => '' } ); %if (@cust_pkg) { Current packages - select to remove (services are moved to a new package below) @@ -18,13 +17,7 @@ </TR> <BR><BR> % -% -% foreach ( sort { $all_pkg{ $a->getfield('pkgpart') } -% cmp $all_pkg{ $b->getfield('pkgpart') } -% } -% @cust_pkg -% ) -% { +% foreach ( @main_pkgs ) { % my($pkgnum,$pkgpart)=( $_->getfield('pkgnum'), $_->getfield('pkgpart') ); % my $checked = $remove_pkg{$pkgnum} ? ' CHECKED' : ''; % @@ -36,6 +29,13 @@ <TD ALIGN="right"><% $pkgnum %>:</TD> <TD><% $all_pkg{$pkgpart} %> - <% $all_comment{$pkgpart} %></TD> </TR> +% foreach my $supp_pkg ( @{ $supp_pkgs_of{$pkgnum} } ) { + <TR> + <TD></TD> + <TD></TD> + <TD>+ <% $all_pkg{$supp_pkg->pkgpart} %> - <% $all_comment{$supp_pkg->pkgpart} %></TD> + </TR> +% } % } @@ -147,4 +147,24 @@ if ( $cgi->param('error') ) { my $p1 = popurl(1); +my @cust_pkg = qsearch('cust_pkg', { 'custnum' => $custnum, 'cancel' => '' } ); +my @main_pkgs; +my %supp_pkgs_of; # main pkgnum => arrayref of cust_pkgs + + +foreach my $cust_pkg + ( sort { $all_pkg{ $a->pkgpart } cmp $all_pkg{ $b->getfield('pkgpart') } } + @cust_pkg + ) + # XXX does not properly handle recursive supplemental links +{ + if ( my $main_pkgnum = $cust_pkg->main_pkgnum ) { + $supp_pkgs_of{$main_pkgnum} ||= []; + push @{ $supp_pkgs_of{$main_pkgnum} }, $cust_pkg; + } else { + push @main_pkgs, $cust_pkg; + $supp_pkgs_of{$cust_pkg->pkgnum} ||= []; + } +} + </%init> diff --git a/httemplate/edit/cust_pkg_detail.html b/httemplate/edit/cust_pkg_detail.html index 009ed5c6e..5e107066d 100644 --- a/httemplate/edit/cust_pkg_detail.html +++ b/httemplate/edit/cust_pkg_detail.html @@ -28,7 +28,7 @@ <TR> <TD ALIGN="right">Comment</TD> - <TD BGCOLOR="#ffffff"><% $part_pkg->comment %></TD> + <TD BGCOLOR="#ffffff"><% $part_pkg->comment |h %></TD> </TR> <TR> diff --git a/httemplate/edit/cust_pkg_quantity.html b/httemplate/edit/cust_pkg_quantity.html new file mode 100755 index 000000000..ec47ed6cb --- /dev/null +++ b/httemplate/edit/cust_pkg_quantity.html @@ -0,0 +1,49 @@ +<& /elements/header-popup.html, "Change Quantity" &> +<& /elements/error.html &> + +<FORM ACTION="<% $p %>edit/process/cust_pkg_quantity.html" METHOD=POST> +<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> +<& /elements/table-grid.html, 'bgcolor' => '#cccccc', 'cellpadding' => 2 &> + + <TR> + <TH ALIGN="right">Current package </TH> + <TD CLASS="grid"> + <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B> - <% $part_pkg->comment |h %> + </TD> + </TR> + +<& /elements/tr-input-text.html, + 'field' => 'quantity', + 'curr_value' => $cust_pkg->quantity, + 'label' => emt('Quantity') +&> + +</TABLE> + +<BR> +<INPUT NAME="submit" TYPE="submit" VALUE="Change"> + +</FORM> +</BODY> +</HTML> + +<%init> + +#some false laziness w/misc/change_pkg.cgi + +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $pkgnum = scalar($cgi->param('pkgnum')); +$pkgnum =~ /^(\d+)$/ or die "illegal pkgnum $pkgnum"; +$pkgnum = $1; + +my $cust_pkg = FS::cust_pkg->by_key($pkgnum) or die "unknown pkgnum $pkgnum"; + +my $part_pkg = $cust_pkg->part_pkg; + +</%init> diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi index 656d5ebb5..df42e63ae 100755 --- a/httemplate/edit/cust_refund.cgi +++ b/httemplate/edit/cust_refund.cgi @@ -59,12 +59,12 @@ </TD> </TR> % } - +% if ( $cust_pay->processor ) { <TR> <TD ALIGN="right">Processor</TD> <TD BGCOLOR="#ffffff"><% $cust_pay->processor %></TD> </TR> -% if ( length($auth) ) { +% if ( length($cust_pay->auth) ) { <TR> <TD ALIGN="right">Authorization</TD> @@ -78,10 +78,10 @@ <TD BGCOLOR="#ffffff"><% $cust_pay->order_number %></TD> </TR> % } -% } #if $cust_pay +% } # if ($cust_pay->processor) </TABLE> -% } +% } #if $cust_pay <BR>Refund diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index a24f23805..3e6bd5bec 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -329,6 +329,7 @@ Example: % qw( country ), #select-country % qw( width height ), #htmlarea % qw( alt_format ), #select-cust_location +% qw( classnum ), # select-inventory_item % ; % % #select-table diff --git a/httemplate/edit/elements/part_svc_column.html b/httemplate/edit/elements/part_svc_column.html new file mode 100644 index 000000000..d03c49d2f --- /dev/null +++ b/httemplate/edit/elements/part_svc_column.html @@ -0,0 +1,303 @@ +<%doc> +To be called from part_svc.cgi. +<& elements/part_svc_column.html, + 'svc_acct', + # options... + 'part_svc' => $part_svc, # the existing part_svc to edit + 'clone' => 0, # or a svcpart to clone from +&> + +</%doc> +<%once> +# the semantics of this could be better + +# all of these conditions are when NOT to allow that flag choice +# don't allow the 'inventory' flags (M, A) to be chosen for +# fields that aren't free-text +my $inv_sub = sub { $_[0]->{disable_inventory} || $_[0]->{type} ne 'text' }; +tie my %flag, 'Tie::IxHash', + '' => { 'desc' => 'No default', 'condition' => sub { 0 } }, + 'D' => { 'desc' => 'Default', + 'condition' => + sub { $_[0]->{disable_default } } + }, + 'F' => { 'desc' => 'Fixed (unchangeable)', + 'condition' => + sub { $_[0]->{disable_fixed} }, + }, + 'S' => { 'desc' => 'Selectable Choice', + 'condition' => + sub { $_[0]->{disable_select} }, + }, + 'M' => { 'desc' => 'Manual selection from inventory', + 'condition' => $inv_sub, + }, + 'A' => { 'desc' => 'Automatically fill in from inventory', + 'condition' => $inv_sub, + }, + 'H' => { 'desc' => 'Select from hardware class', + 'condition' => sub { $_[0]->{type} ne 'select-hardware' }, + }, + 'X' => { 'desc' => 'Excluded', + 'condition' => sub { 1 }, # obsolete + }, +; + +# the semantics of this could be much better +sub flag_condition { + my $f = shift; + not &{ $flag{$f}->{'condition'} }(@_); +} + +my %communigate_fields = ( + 'svc_acct' => { map { $_=>1 } + qw( file_quota file_maxnum file_maxsize + password_selfchange password_recover + ), + grep /^cgp_/, fields('svc_acct') + }, + 'svc_domain' => { map { $_=>1 } + qw( max_accounts trailer parent_svcnum ), + grep /^(cgp|acct_def)_/, fields('svc_domain') + }, +); +</%once> +<INPUT TYPE="hidden" NAME="svcdb" VALUE="<% $svcdb %>"> +<BR><BR> +<& /elements/table.html &> + <TR><TH COLSPAN=<% $columns %>>Exports</TH></TR> + <TR> +% # exports +% foreach my $part_export (@part_export) { + <TD> + <INPUT TYPE="checkbox" \ + NAME="exportnum<% $part_export->exportnum %>" \ + VALUE=1 \ + <% $has_export_svc{$part_export->exportnum} ? 'CHECKED' : '' %>> + <% $part_export->label_html %> + </TD> +% $count++; +% if ( $count % $columns == 0 ) { + </TR> + <TR> +% } +% } + </TR> +</TABLE><BR><BR> +For the selected table, you can give fields default or fixed (unchangeable) +values, or select an inventory class to manually or automatically fill in +that field. +<& /elements/table-grid.html, cellpadding => 4 &> + <TR> + <TH BGCOLOR="#cccccc">Field</TH> + <TH BGCOLOR="#cccccc">Label</TH> + <TH BGCOLOR="#cccccc" COLSPAN=2>Modifier</TH> + </TR> +% $part_svc->set('svcpart' => $opt{'clone'}) if $opt{'clone'}; # for now +% my $i = 0; +% foreach my $field (@fields) { +% my $def = shift @defs; +% my $part_svc_column = $part_svc->part_svc_column($field); +% my $flag = $part_svc_column->columnflag; +% my $formatter = $def->{'format'} || sub { shift }; +% my $value = &{$formatter}($part_svc_column->columnvalue); + <TR CLASS="row<%$i%>"> + <TD ROWSPAN=2 CLASS="grid" ALIGN="right"> + <% $def->{'label'} || $field %> + </TD> + <TD ROWSPAN=2 CLASS="grid"> + <INPUT NAME="<% $svcdb %>__<% $field %>_label" + STYLE="text-align: right" + VALUE="<% $part_svc_column->columnlabel || $def->{'label'} |h %>"> + </TD> + + <TD ROWSPAN=1 CLASS="grid"> +% # flag selection +% if ( $def->{'type'} eq 'disabled' ) { +% $flag = ''; + No default +% } else { +% my $name = $svcdb.'__'.$field.'_flag'; + <SELECT NAME="<%$name%>" + ID="<%$name%>" + STYLE="width:100%" + onchange="flag_changed(this)"> +% foreach my $f (keys %flag) { +% if ( flag_condition($f, $def, $svcdb, $field) ) { + <OPTION VALUE="<%$f%>"<% $flag eq $f ? ' SELECTED' : ''%>> + <% $flag{$f}->{desc} %> + </OPTION> +% } +% } + </SELECT> +% } # if $def->{'type'} eq 'disabled' + </TD> + <TD CLASS="grid"> +% # value entry/selection +% my $name = $svcdb.'__'.$field; +% # These are all MANDATORY SELECT types. Regardless of the flag value, +% # there will never be a text input (either in svc_* or in part_svc) for +% # these fields. +% if ( $def->{'type'} eq 'checkbox' ) { + <& /elements/checkbox.html, + 'field' => $name, + 'curr_value' => $value, + 'value' => 'Y' &> +% +% } elsif ( $def->{'type'} eq 'select' ) { +% +% if ( $def->{'select_table'} ) { + <& /elements/select-table.html, + 'field' => $name, + 'id' => $name.'_select', + 'table' => $def->{'select_table'}, + 'name_col' => $def->{'select_label'}, + 'value_col' => $def->{'select_key'}, + 'order_by' => dbdef->table($def->{'select_table'})->primary_key, + 'multiple' => $def->{'multiple'}, + 'disable_empty' => 1, + 'curr_value' => $value, + &> +% } else { +% my (@options, %labels); +% if ( $def->{'select_list'} ) { +% @options = @{ $def->{'select_list'} }; +% @labels{@options} = @options; +% } elsif ( $def->{'select_hash'} ) { +% if ( ref($def->{'select_hash'}) eq 'ARRAY' ) { +% tie my %hash, 'Tie::IxHash', @{ $def->{'select_hash'} }; +% $def->{'select_hash'} = \%hash; +% } +% @options = keys( %{ $def->{'select_hash'} } ); +% %labels = %{ $def->{'select_hash'} }; +% } + <& /elements/select.html, + 'field' => $name, + 'id' => $name.'_select', + 'options' => \@options, + 'labels' => \%labels, + 'multiple' => $def->{'multiple'}, + 'curr_value' => $value, + &> +% } +% } elsif ( $def->{'type'} =~ /select-(.*?).html/ ) { + <& '/elements/'.$def->{'type'}, + 'field' => $name, + 'id' => $name.'_select', + 'multiple' => $def->{'multiple'}, + 'curr_value' => $value, + &> +% } elsif ( $def->{'type'} eq 'communigate_pro-accessmodes' ) { + <& /elements/communigate_pro-accessmodes.html, + 'element_name_prefix' => $name.'_', + 'curr_value' => $value, + &> +% } elsif ( $def->{'type'} eq 'textarea' ) { +% # special cases + <TEXTAREA NAME="<%$name%>"><% $value |h %></TEXTAREA> +% } elsif ( $def->{'type'} eq 'disabled' ) { + <INPUT TYPE="hidden" NAME="<%$name%>" VALUE=""> +% } else { +% # the normal case: a text input, and a _select which is an inventory +% # or hardware class + <INPUT TYPE="text" + NAME="<%$name%>" + ID="<%$name%>" + VALUE="<%$value%>"> +% # inventory class selection + <& /elements/select-table.html, + 'field' => $name.'_classnum', + 'id' => $name.'_select', + 'table' => 'inventory_class', + 'name_col' => 'classname', + 'curr_value' => $value, + 'empty_label' => 'Select inventory class', + 'multiple' => 1, + &> +% } + </TD> + </TR> + <TR CLASS="row<%$i%>"> + <TD COLSPAN=2 CLASS="def_info"> +% if ( $def->{def_info} ) { + (<% $def->{def_info} %>) + </TD> + </TR> +% } +% $i = 1-$i; +% } # foreach my $field +% +% # special case: svc_acct password edit ACL +% if ( $svcdb eq 'svc_acct' ) { +% push @fields, 'restrict_edit_password'; + <TR> + <TD COLSPAN=3 ALIGN="right"> + <% emt('Require "Provision" access right to edit password') %> + </TD> + <TD> + <INPUT TYPE="checkbox" NAME="restrict_edit_password" VALUE="Y" \ + <% $part_svc->restrict_edit_password ? 'CHECKED' : '' %>> + </TD> + </TR> +% } +</TABLE> +<& /elements/progress-init.html, + $svcdb, #form name + [ # form fields to send + qw(svc svcpart classnum selfservice_access disabled preserve exportnum), + @fields + ], + 'process/part_svc.cgi', # target + $p.'browse/part_svc.cgi', # redirect landing + $svcdb, #key +&> +% $svcpart = '' if $opt{clone}; +<BR> +<INPUT NAME="submit" + TYPE="button" + VALUE="<% emt($svcpart ? 'Apply changes' : 'Add service') %>" + onclick="fixup_submit('<%$svcdb%>')" +> +<%init> +my $svcdb = shift; +my %opt = @_; +my $columns = 3; +my $count = 0; +my $communigate = 0; +my $conf = FS::Conf->new; + +my $part_svc = $opt{'part_svc'} || FS::part_svc->new; + +my @part_export; +my $export_info = FS::part_export::export_info($svcdb); +foreach (keys %{ $export_info }) { + push @part_export, qsearch('part_export', { exporttype => $_ }); +} +$communigate = scalar(grep {$_->exporttype =~ /^communigate/} @part_export); + +my $svcpart = $opt{'clone'} || $part_svc->svcpart; +my %has_export_svc; +if ( $svcpart ) { + foreach (qsearch('export_svc', { svcpart => $svcpart })) { + $has_export_svc{$_->exportnum} = 1; + } +} + +my @fields; +if ( defined( dbdef->table($svcdb) ) ) { # when is it ever not defined? + @fields = grep { + $_ ne 'svcnum' + and ( $communigate || ! $communigate_fields{$svcdb}->{$_} ) + and ( !FS::part_svc->svc_table_fields($svcdb)->{$_}->{disable_part_svc_column} + || $part_svc->part_svc_column($_)->columnflag ) + } fields($svcdb); +} +if ( $svcdb eq 'svc_acct' + or ( $svcdb eq 'svc_broadband' and $conf->exists('svc_broadband-radius') ) + ) +{ + push @fields, 'usergroup'; +} + +my @defs = map { FS::part_svc->svc_table_fields($svcdb)->{$_} } @fields; +</%init> diff --git a/httemplate/edit/elements/svc_Common.html b/httemplate/edit/elements/svc_Common.html index 0d9d36c07..d46d1cb42 100644 --- a/httemplate/edit/elements/svc_Common.html +++ b/httemplate/edit/elements/svc_Common.html @@ -88,30 +88,13 @@ } elsif ( $flag eq 'A' ) { $f->{'type'} = 'hidden'; } elsif ( $flag eq 'M' ) { + $f->{'type'} = 'select-inventory_item'; $f->{'empty_label'} = 'Select inventory item'; - $f->{'type'} = 'select-table'; - $f->{'table'} = 'inventory_item'; - $f->{'name_col'} = 'item'; - $f->{'value_col'} = 'item'; - $f->{'agent_virt'} = 1; - $f->{'agent_null'} = 1; - $f->{'hashref'} = { - 'classnum'=>$columndef->columnvalue, - #'svcnum' => '', - }; - $f->{'extra_sql'} = 'AND ( svcnum IS NULL '; - $f->{'extra_sql'} .= ' OR svcnum = '. $object->svcnum - if $object->svcnum; - $f->{'extra_sql'} .= ' ) '; + $f->{'extra_sql'} = 'WHERE ( svcnum IS NULL ' . + ($object->svcnum && ' OR svcnum = '.$object->svcnum) . + ')'; + $f->{'classnum'} = $columndef->columnvalue; $f->{'disable_empty'} = $object->svcnum ? 1 : 0; - if ( $f->{'field'} eq 'mac_addr' ) { - $f->{'compare_sub'} = sub { - my($a, $b) = @_; - $a =~ s/[-: ]//g; - $b =~ s/[-: ]//g; - lc($a) eq lc($b); - }; - } } elsif ( $flag eq 'H' ) { $f->{'type'} = 'select-hardware_type'; $f->{'hashref'} = { diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi index 4dd253be8..2897cf39d 100644 --- a/httemplate/edit/part_export.cgi +++ b/httemplate/edit/part_export.cgi @@ -2,6 +2,34 @@ <% include('/elements/error.html') %> +<SCRIPT TYPE="text/javascript"> + function svc_machine_changed (what, layer) { + if ( what.checked ) { + var machine = document.getElementById(layer + "_machine"); + var part_export_machine = + document.getElementById(layer + "_part_export_machine"); + if ( what.value == 'Y' ) { + machine.disabled = true; + part_export_machine.disabled = false; + } else if ( what.value == 'N' ) { + machine.disabled = false; + part_export_machine.disabled = true; + } + } + } + + function part_export_machine_changed (what, layer) { + var select_default = document.getElementById(layer + '_default_machine'); + var selected = select_default.value; + select_default.options.length = 0; + var choices = what.value.split("\n"); + for (var i = 0; i < choices.length; i++) { + select_default.options[i] = new Option(choices[i]); + } + select_default.value = selected; + } + +</SCRIPT> <FORM NAME="dummy"> <INPUT TYPE="hidden" NAME="exportnum" VALUE="<% $part_export->exportnum %>"> @@ -58,7 +86,6 @@ my $widget = new HTML::Widgets::SelectLayers( 'form_name' => 'dummy', 'form_action' => 'process/part_export.cgi', 'form_text' => [qw( exportnum exportname )], -# 'form_checkbox' => [qw()], 'html_between' => "</TD></TR></TABLE>\n", 'layer_callback' => sub { my $layer = shift; @@ -87,7 +114,8 @@ my $widget = new HTML::Widgets::SelectLayers( if ( $exports->{$layer}{svc_machine} ) { my( $N_CHK, $Y_CHK) = ( 'CHECKED', '' ); my( $machine_DISABLED, $pem_DISABLED) = ( '', 'DISABLED' ); - my $part_export_machine = ''; + my @part_export_machine; + my $default_machine = ''; if ( $cgi->param('svc_machine') eq 'Y' || $machine eq '_SVC_MACHINE' ) @@ -97,38 +125,43 @@ my $widget = new HTML::Widgets::SelectLayers( $machine_DISABLED = 'DISABLED'; $pem_DISABLED = ''; $machine = ''; - $part_export_machine = - $cgi->param('part_export_machine') - || join "\n", + @part_export_machine = $cgi->param('part_export_machine'); + if (!@part_export_machine) { + @part_export_machine = map $_->machine, grep ! $_->disabled, $part_export->part_export_machine; + } + $default_machine = + $cgi->param('default_machine_name') + || $part_export->default_export_machine; } - my $oc = qq(onChange="${layer}_svc_machine_changed(this)"); + my $oc = qq(onChange="svc_machine_changed(this, '$layer')"); $html .= qq[ <INPUT TYPE="radio" NAME="svc_machine" VALUE="N" $N_CHK $oc> <INPUT TYPE="text" NAME="machine" ID="${layer}_machine" VALUE="$machine" $machine_DISABLED> <BR> <INPUT TYPE="radio" NAME="svc_machine" VALUE="Y" $Y_CHK $oc> - Selected in each customer service from these choices - <TEXTAREA NAME="part_export_machine" ID="${layer}_part_export_machine" $pem_DISABLED>$part_export_machine</TEXTAREA> - - <SCRIPT TYPE="text/javascript"> - function ${layer}_svc_machine_changed (what) { - if ( what.checked ) { - var machine = document.getElementById("${layer}_machine"); - var part_export_machine = document.getElementById("${layer}_part_export_machine"); - if ( what.value == 'Y' ) { - machine.disabled = true; - part_export_machine.disabled = false; - } else if ( what.value == 'N' ) { - machine.disabled = false; - part_export_machine.disabled = true; - } - } - } - </SCRIPT> + <DIV STYLE="display:inline-block; vertical-align: top; text-align: right"> + Selected in each customer service from these choices: + <TEXTAREA STYLE="vertical-align: top" NAME="part_export_machine" + ID="${layer}_part_export_machine" + onchange="part_export_machine_changed(this, '$layer')" + $pem_DISABLED>] . + + join("\n", @part_export_machine) . + + qq[</TEXTAREA> + <BR> + Default: + <SELECT NAME="default_machine_name" ID="${layer}_default_machine"> ]; + foreach (@part_export_machine) { + $_ = encode_entities($_); # oh noes, XSS + my $sel = ($default_machine eq $_) ? ' SELECTED' : ''; + $html .= qq!<OPTION VALUE="$_"$sel>$_</OPTION>\n!; + } + $html .= '</DIV></SELECT>' } else { $html .= qq(<INPUT TYPE="text" NAME="machine" VALUE="$machine">). '<INPUT TYPE="hidden" NAME="svc_machine" VALUE=N">'; diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index c3f4f88b6..fadde354e 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -28,7 +28,8 @@ 'labels' => { 'pkgpart' => 'Package Definition', - 'pkg' => 'Package (customer-visible)', + 'pkg' => 'Package', + %locale_field_labels, 'comment' => 'Comment (customer-hidden)', 'classnum' => 'Package class', 'addon_classnum' => 'Restrict additional orders to package class', @@ -53,6 +54,7 @@ 'discountnum' => 'Offer discounts for longer terms', 'bill_dst_pkgpart' => 'Include line item(s) from package', 'svc_dst_pkgpart' => 'Include services of package', + 'supp_dst_pkgpart' => 'Include complete package', 'report_option' => 'Report classes', 'fcc_ds0s' => 'Voice-grade equivalents', 'fcc_voip_class' => 'Category', @@ -79,6 +81,7 @@ size => 40, #32 maxlength => 50, }, + #@locale_fields, {field=>'comment', type=>'text', size=>40 }, #32 { field => 'agentnum', type => 'select-agent', @@ -239,6 +242,19 @@ }, { 'type' => 'tablebreak-tr-title', + 'value' => 'Supplemental packages', + 'colspan' => '4', + }, + { 'field' => 'supp_dst_pkgpart', + 'type' => 'select-part_pkg', + 'm2_label' => 'Include complete package', + 'm2m_method' => 'supp_part_pkg_link', + 'm2m_dstcol' => 'dst_pkgpart', + 'm2_error_callback' => + &{$m2_error_callback_maker}('supp'), + }, + + { 'type' => 'tablebreak-tr-title', 'value' => 'Pricing add-ons', 'colspan' => 4, }, @@ -323,6 +339,22 @@ my $agent_clone_extra_sql = my $conf = new FS::Conf; my $taxproducts = $conf->exists('enable_taxproducts'); +my @locales = grep { ! /^en_/i } $conf->config('available-locales'); #should filter from the default locale lang instead of en_ +my %locale_labels = map { + ( $_ => 'Package -- '. FS::Locales->description($_) ) +} @locales; +@locales = + sort { $locale_labels{$a} cmp $locale_labels{$b} } + @locales; + +my $n = 0; +my %locale_field_labels = ( + map { + ( 'pkgpartmsgnum'. $n++. '_pkg' => $locale_labels{$_} ); + } + @locales +); + my $sth = dbh->prepare("SELECT COUNT(*) FROM part_pkg_report_option". " WHERE disabled IS NULL OR disabled = '' ") or die dbh->errstr; @@ -354,6 +386,42 @@ my $recur_show_zero_disabled = 1; my $pkgpart = ''; +my $splice_locale_fields = sub { + my( $fields, $pkey_value_callback, $pkg_value_callback ) = @_; + + my $n = 0; + my @locale_fields = ( + map { + my $pkey_value= $pkey_value_callback ? &$pkey_value_callback($_) : ''; + my $pkg_value = $pkg_value_callback + ? $pkg_value_callback eq 'cgiparam' + ? $cgi->param('pkgpartmsgnum'. $n. '_pkg') + : &$pkg_value_callback($_) + : ''; + ( + { field => 'pkgpartmsgnum'. $n, + type => 'hidden', + value => $pkey_value, + }, + { field => 'pkgpartmsgnum'. $n. '_locale', + type => 'hidden', + value => $_, + }, + { field => 'pkgpartmsgnum'. $n++. '_pkg', + type => 'text', + size => 40, + #maxlength => 50, + value => $pkg_value, + }, + ); + + } + @locales + ); + splice(@$fields, 7, 0, @locale_fields); #XXX 7 is arbitrary above + +}; + my $error_callback = sub { my($cgi, $object, $fields, $opt ) = @_; @@ -394,6 +462,16 @@ my $error_callback = sub { $pkgpart = $object->pkgpart; + &$splice_locale_fields( + $fields, + sub { + my $locale = shift; + my $part_pkg_msgcat = $object->part_pkg_msgcat($locale); + $part_pkg_msgcat ? $part_pkg_msgcat->pkgpartmsgnum : ''; + }, + 'cgiparam' + ); + }; my $new_hashref_callback = sub { { 'plan' => 'flat' }; }; @@ -459,6 +537,20 @@ my $edit_callback = sub { $pkgpart = $object->pkgpart; + &$splice_locale_fields( + $fields, + sub { + my $locale = shift; + my $part_pkg_msgcat = $object->part_pkg_msgcat($locale); + $part_pkg_msgcat ? $part_pkg_msgcat->pkgpartmsgnum : ''; + }, + sub { + my $locale = shift; + my $part_pkg_msgcat = $object->part_pkg_msgcat($locale); + $part_pkg_msgcat ? $part_pkg_msgcat->pkg : ''; + } + ); + }; my $new_callback = sub { @@ -473,6 +565,8 @@ my $new_callback = sub { $options{'suspend_bill'}=1 if $conf->exists('part_pkg-default_suspend_bill'); + &$splice_locale_fields($fields, '', ''); + }; my $clone_callback = sub { @@ -506,6 +600,16 @@ my $clone_callback = sub { foreach (qw( setup_fee recur_fee disable_line_item_date_ranges )); $recur_disabled = $object->freq ? 0 : 1; + + &$splice_locale_fields( + $fields, + '', + sub { + my $locale = shift; + my $part_pkg_msgcat = $object->part_pkg_msgcat($locale); + $part_pkg_msgcat ? $part_pkg_msgcat->pkg : ''; + } + ); }; my $discount_error_callback = sub { diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index 007c24629..58c237efd 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -1,11 +1,111 @@ -<& /elements/header.html, "$action Service Definition", - menubar('View all service definitions' => "${p}browse/part_svc.cgi"), +<& /elements/header.html, "$action Service Definition" &> +<& /elements/menubar.html, + 'View all service definitions' => "${p}browse/part_svc.cgi" #" onLoad=\"visualize()\"" &> <& /elements/init_overlib.html &> -<BR> +<BR><BR> + +<STYLE TYPE="text/css"> +.disabled { + background-color: #dddddd; +} +.hidden { + display: none; +} +.enabled { + background-color: #ffffff; +} +.row0 TD { + background-color: #eeeeee; +} +.row1 TD { + background-color: #ffffff; +} +.def_info { + text-align: center; + padding: 0px; + border-top: none; + font-size: smaller; + font-style: italic; +} +</STYLE> +<SCRIPT TYPE="text/javascript"> +function fixup_submit(layer) { + document.forms[layer].submit.disabled = true; + fixup(document.forms[layer]); + window[layer+'process'].call(); +} + +function flag_changed(obj) { + var newflag = obj.value; + var a = obj.name.match(/(.*)__(.*)_flag/); + var layer = a[1]; + var field = a[2]; + var input = document.getElementById(layer + '__' + field); + // for fields that have both 'input' and 'select', 'select' is 'select from + // inventory class'. + var select = document.getElementById(layer + '__' + field + '_select'); + if (newflag == "" || newflag == "X") { // disable + if ( input ) { + input.disabled = true; + input.className = 'disabled'; + } + if ( select ) { + select.disabled = true; + select.className = 'hidden'; + } + } else if ( newflag == 'D' || newflag == 'F' || newflag == 'S' ) { + if ( input ) { + // enable text box, disable inventory select + input.disabled = false; + input.className = 'enabled'; + if ( select ) { + select.disabled = false; + select.className = 'hidden'; + } + } else if ( select ) { + // enable select + select.disabled = false; + select.className = 'enabled'; + if ( newflag == 'S' || select.getAttribute('should_be_multiple') ) { + select.multiple = true; + } else { + select.multiple = false; + } + } + } else if ( newflag == 'M' || newflag == 'A' || newflag == 'H' ) { + // these all require a class selection + if ( select ) { + select.disabled = false; + select.className = 'enabled'; + if ( input ) { + input.disabled = false; + input.className = 'hidden'; + } + } + } +} + +window.onload = function() { + var selects = document.getElementsByTagName('SELECT'); + for(i = 0; i < selects.length; i++) { + var obj = selects[i]; + if ( obj.multiple ) { + obj.setAttribute('should_be_multiple', true); + } + } + for(i = 0; i < selects.length; i++) { + var obj = selects[i]; + if ( obj.name.match(/_flag$/) ) { + flag_changed(obj); + } + } +}; + +</SCRIPT> <FORM NAME="dummy"> @@ -53,386 +153,6 @@ <BR> -% my %vfields; -% #code duplication w/ edit/part_svc.cgi, should move this hash to part_svc.pm -% # and generalize the subs -% # condition sub is tested to see whether to disable display of this choice -% # params: ( $def, $layer, $field ) (see SUB below) -% my $inv_sub = sub { -% $_[0]->{disable_inventory} -% || $_[0]->{'type'} ne 'text' -% }; -% tie my %flag, 'Tie::IxHash', -% '' => { 'desc' => 'No default', }, -% 'D' => { 'desc' => 'Default', -% 'condition' => -% sub { $_[0]->{disable_default} }, -% }, -% 'F' => { 'desc' => 'Fixed (unchangeable)', -% 'condition' => -% sub { $_[0]->{disable_fixed} }, -% }, -% 'S' => { 'desc' => 'Selectable Choice', -% 'condition' => -% sub { !ref($_[0]) || $_[0]->{disable_select} }, -% }, -% 'M' => { 'desc' => 'Manual selection from inventory', -% 'condition' => $inv_sub, -% }, -% 'A' => { 'desc' => 'Automatically fill in from inventory', -% 'condition' => $inv_sub, -% }, -% 'H' => { 'desc' => 'Select from hardware class', -% 'condition' => sub { $_[0]->{type} ne 'select-hardware' }, -% }, -% 'X' => { 'desc' => 'Excluded', -% 'condition' => -% sub { ! $vfields{$_[1]}->{$_[2]} }, -% -% }, -% ; -% -% my @dbs = $hashref->{svcdb} -% ? ( $hashref->{svcdb} ) -% : FS::part_svc->svc_tables(); -% -% my $help = ''; -% unless ( $hashref->{svcpart} ) { -% $help = ' '. -% include('/elements/popup_link.html', -% 'action' => $p.'docs/part_svc-table.html', -% 'label' => 'help', -% 'actionlabel' => 'Service table help', -% 'width' => 763, -% #'height' => 400, -% ); -% } -% -% tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs; -% my $widget = new HTML::Widgets::SelectLayers( -% #'selected_layer' => $p_svcdb, -% 'selected_layer' => $hashref->{svcdb} || 'svc_acct', -% 'options' => \%svcdb, -% 'form_name' => 'dummy', -% #'form_action' => 'process/part_svc.cgi', -% 'form_action' => 'part_svc.cgi', #self -% 'form_elements' => [qw( svc svcpart classnum selfservice_access -% disabled preserve -% )], -% 'html_between' => $help, -% 'layer_callback' => sub { -% my $layer = shift; -% -% my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!; -% -% #$html .= $svcdb_info; -% -% my $columns = 3; -% my $count = 0; -% my $communigate = 0; -% my @part_export = -% map { qsearch( 'part_export', {exporttype => $_ } ) } -% keys %{FS::part_export::export_info($layer)}; -% $html .= '<BR><BR>'. include('/elements/table.html') . -% "<TR><TH COLSPAN=$columns>Exports</TH></TR><TR>"; -% foreach my $part_export ( @part_export ) { -% $communigate++ if $part_export->exporttype =~ /^communigate/; -% $html .= '<TD><INPUT TYPE="checkbox"'. -% ' NAME="exportnum'. $part_export->exportnum. '" VALUE="1" '; -% $html .= 'CHECKED' -% if ( $clone || $part_svc->svcpart ) #null svcpart search causing error -% && qsearchs( 'export_svc', { -% exportnum => $part_export->exportnum, -% svcpart => $clone || $part_svc->svcpart }); -% $html .= '>'. $part_export->label_html. '</TD>'; -% $count++; -% $html .= '</TR><TR>' unless $count % $columns; -% } -% $html .= '</TR></TABLE><BR><BR>'. $mod_info; -% -% $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>'; -% -% my $bgcolor1 = '#eeeeee'; -% my $bgcolor2 = '#ffffff'; -% my $bgcolor; -% -% #yucky kludge -% my @fields = (); -% if ( defined( dbdef->table($layer) ) ) { -% @fields = grep { -% $_ ne 'svcnum' -% && ( $communigate || !$communigate_fields{$layer}->{$_} ) -% && ( !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' -% or ( $layer eq 'svc_broadband' and -% $conf->exists('svc_broadband-radius') ); # double kludge -% # (but we do want to check the config, right?) -% $part_svc->svcpart($clone) if $clone; #haha, undone below -% -% -% foreach my $field (@fields) { -% -% #a few lines of false laziness w/browse/part_svc.cgi -% my $def = FS::part_svc->svc_table_fields($layer)->{$field}; -% 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; -% -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } -% -% $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">!; -% -% if ( $def->{type} eq 'disabled' ) { -% -% $html .= 'No default'; -% -% } else { -% -% $html .= qq!<SELECT NAME="${layer}__${field}_flag"!. -% qq! onChange="${layer}__${field}_flag_changed(this)">!; -% -% foreach my $f ( keys %flag ) { -% -% # need to template-ize more httemplate/edit/svc_* first -% next if $f eq 'M' and $layer !~ /^svc_(broadband|external|phone|dish)$/; -% -% #here is where the SUB from above is called, to skip some choices -% next if $flag{$f}->{condition} -% && &{ $flag{$f}->{condition} }( $def, $layer, $field ); -% -% $html .= qq!<OPTION VALUE="$f"!. -% ' SELECTED'x($flag eq $f ). -% '>'. $flag{$f}->{desc}; -% -% } -% -% $html .= '</SELECT>'; -% -% $html .= join("\n", -% '<SCRIPT>', -% " function ${layer}__${field}_flag_changed(what) {", -% ' var f = what.options[what.selectedIndex].value;', -% ' if ( f == "" || f == "X" ) { //disable', -% " what.form.${layer}__${field}.disabled = true;". -% " what.form.${layer}__${field}.style.backgroundColor = '#dddddd';". -% " if ( what.form.${layer}__${field}_classnum ) {". -% " what.form.${layer}__${field}_classnum.disabled = true;". -% " what.form.${layer}__${field}_classnum.style.backgroundColor = '#dddddd';". -% " }". -% ' } else if ( f == "D" || f == "F" || f =="S" ) { //enable, text box', -% " what.form.${layer}__${field}.disabled = false;". -% " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';". -% " if ( f == 'S' || '${field}' == 'usergroup' ) {". # kludge -% " what.form.${layer}__${field}.multiple = true;". -% " } else {". -% " what.form.${layer}__${field}.multiple = false;". -% " }". -% " what.form.${layer}__${field}.style.display = '';". -% " if ( what.form.${layer}__${field}_classnum ) {". -% " what.form.${layer}__${field}_classnum.disabled = false;". -% " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';". -% " what.form.${layer}__${field}_classnum.style.display = 'none';". -% " }". -% ' } else if ( f == "M" || f == "A" || f == "H" ) { '. -% '//enable, inventory', -% " what.form.${layer}__${field}.disabled = false;". -% " what.form.${layer}__${field}.style.backgroundColor = '#ffffff';". -% " what.form.${layer}__${field}.style.display = 'none';". -% " if ( what.form.${layer}__${field}_classnum ) {". -% " what.form.${layer}__${field}_classnum.disabled = false;". -% " what.form.${layer}__${field}_classnum.style.backgroundColor = '#ffffff';". -% " what.form.${layer}__${field}_classnum.style.display = '';". -% " }". -% ' }', -% ' }', -% '</SCRIPT>', -% ); -% -% } -% -% $html .= qq!</TD><TD CLASS="grid" BGCOLOR="$bgcolor">!; -% -% my $disabled = $flag ? '' -% : 'DISABLED STYLE="background-color: #dddddd"'; -% my $nodisplay = ' STYLE="display:none"'; -% -% if ( !$def->{type} || $def->{type} eq 'text' ) { -% -% my $is_inv = ( $flag =~ /^[MA]$/ ); -% -% $html .= -% qq!<INPUT TYPE="text" NAME="${layer}__${field}" VALUE="$value" !. -% $disabled. -% ( $is_inv ? $nodisplay : $disabled ). -% '>'; -% -% $html .= include('/elements/select-table.html', -% 'element_name' => "${layer}__${field}_classnum", -% 'id' => "${layer}__${field}_classnum", -% 'element_etc' => ( $is_inv -% ? $disabled -% : $nodisplay -% ), -% 'table' => 'inventory_class', -% 'name_col' => 'classname', -% 'value' => $value, -% 'empty_label' => 'Select inventory class', -% ); -% -% } elsif ( $def->{type} eq 'checkbox' ) { -% -% $html .= include('/elements/checkbox.html', -% 'field' => $layer.'__'.$field, -% 'curr_value' => $value, -% 'value' => 'Y', -% ); -% -% } elsif ( $def->{type} eq 'select' ) { -% -% $html .= qq!<SELECT NAME="${layer}__${field}" $disabled!; -% $html .= ' MULTIPLE' if $flag eq 'S'; -% $html .= '>'; -% $html .= '<OPTION> </OPTION>' unless $value; -% if ( $def->{select_table} ) { -% foreach my $record ( qsearch( $def->{select_table}, {} ) ) { -% my $rvalue = $record->getfield($def->{select_key}); -% my $select_label = $def->{select_label}; -% $html .= qq!<OPTION VALUE="$rvalue"!. -% (grep(/^$rvalue$/, split(',',$value)) ? ' SELECTED>' : '>' ). -% $record->$select_label(). '</OPTION>'; -% } #next $record -% } elsif ( $def->{select_list} ) { -% foreach my $item ( @{$def->{select_list}} ) { -% $html .= qq!<OPTION VALUE="$item"!. -% (grep(/^$item$/, split(',',$value)) ? ' SELECTED>' : '>' ). -% $item. '</OPTION>'; -% } #next $item -% } elsif ( $def->{select_hash} ) { -% if ( ref($def->{select_hash}) eq 'ARRAY' ) { -% tie my %hash, 'Tie::IxHash', @{ $def->{select_hash} }; -% $def->{select_hash} = \%hash; -% } -% foreach my $key ( keys %{$def->{select_hash}} ) { -% $html .= qq!<OPTION VALUE="$key"!. -% (grep(/^$key$/, split(',',$value)) ? ' SELECTED>' : '>' ). -% $def->{select_hash}{$key}. '</OPTION>'; -% } #next $key -% } #endif -% $html .= '</SELECT>'; -% -% } elsif ( $def->{type} eq 'textarea' ) { -% -% $html .= -% qq!<TEXTAREA NAME="${layer}__${field}">!. encode_entities($value). -% '</TEXTAREA>'; -% -% } elsif ( $def->{type} =~ /select-(.*?).html/ ) { -% -% $html .= include("/elements/".$def->{type}, -% 'curr_value' => $value, -% 'element_name' => "${layer}__${field}", -% 'element_etc' => $disabled, -% 'multiple' => ($def->{multiple} || -% $flag eq 'S'), -% # allow the table def to force 'multiple' -% ); -% -% } elsif ( $def->{type} eq 'communigate_pro-accessmodes' ) { -% -% $html .= include('/elements/communigate_pro-accessmodes.html', -% 'element_name_prefix' => "${layer}__${field}_", -% 'curr_value' => $value, -% #doesn't work#'element_etc' => $disabled, -% ); -% -% } elsif ( $def->{type} eq 'select-hardware' ) { -% -% $html .= qq!<INPUT TYPE="text" NAME="${layer}__${field}" $disabled>!; -% $html .= include('/elements/select-hardware_class.html', -% 'curr_value' => $value, -% 'element_name' => "${layer}__${field}_classnum", -% 'id' => "${layer}__${field}_classnum", -% 'element_etc' => $flag ne 'H' && $nodisplay, -% 'empty_label' => 'Select hardware class', -% ); -% -% } elsif ( $def->{type} eq 'disabled' ) { -% -% $html .= -% qq!<INPUT TYPE="hidden" NAME="${layer}__${field}" VALUE="">!; -% -% } else { -% -% $html .= '<font color="#ff0000">unknown type '. $def->{type}; -% -% } -% -% $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) { -% -% $part_svc->svcpart('') if $clone; #undone -% $html .= "</TABLE>"; -% -% $html .= include('/elements/progress-init.html', -% $layer, #form name -% [ qw(svc svcpart classnum selfservice_access -% disabled preserve -% exportnum), -% @fields ], -% 'process/part_svc.cgi', -% $p.'browse/part_svc.cgi', -% $layer, -% ); -% $html .= '<BR><INPUT NAME="submit" TYPE="button" VALUE="'. -% ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '" '. -% ' onClick="document.'. "$layer.submit.disabled=true; ". -% "fixup(document.$layer); $layer". 'process();">'; -% -% #$html .= '<BR><INPUT TYPE="submit" VALUE="'. -% # ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">'; -% -% $html; -% -% }, -% ); - <BR> Table <% $widget->html %> @@ -465,28 +185,43 @@ my $action = $part_svc->svcpart ? 'Edit' : 'Add'; my $hashref = $part_svc->hashref; # my $p_svcdb = $part_svc->svcdb || 'svc_acct'; -my %communigate_fields = ( - 'svc_acct' => { map { $_=>1 } - qw( file_quota file_maxnum file_maxsize - password_selfchange password_recover - ), - grep /^cgp_/, fields('svc_acct') - }, - 'svc_domain' => { map { $_=>1 } - qw( max_accounts trailer parent_svcnum ), - grep /^(cgp|acct_def)_/, fields('svc_domain') - }, - #'svc_forward' => { map { $_=>1 } qw( ) }, - #'svc_mailinglist' => { map { $_=>1 } qw( ) }, - #'svc_cert' => { map { $_=>1 } qw( ) }, -); -my $mod_info = ' -For the selected table, you can give fields default or fixed (unchangable) -values, or select an inventory class to manually or automatically fill in -that field. -'; +my @dbs = $hashref->{svcdb} + ? ( $hashref->{svcdb} ) + : FS::part_svc->svc_tables(); + +my $help = ''; +unless ( $hashref->{svcpart} ) { + $help = ' '. + include('/elements/popup_link.html', + 'action' => $p.'docs/part_svc-table.html', + 'label' => 'help', + 'actionlabel' => 'Service table help', + 'width' => 763, + #'height' => 400, + ); +} +tie my %svcdb, 'Tie::IxHash', map { $_=>$_ } grep dbdef->table($_), @dbs; +my $widget = new HTML::Widgets::SelectLayers( + #'selected_layer' => $p_svcdb, + 'selected_layer' => $hashref->{svcdb} || 'svc_acct', + 'options' => \%svcdb, + 'form_name' => 'dummy', + #'form_action' => 'process/part_svc.cgi', + 'form_action' => 'part_svc.cgi', #self + 'form_elements' => [qw( svc svcpart classnum selfservice_access + disabled preserve + )], + 'html_between' => $help, + 'layer_callback' => sub { + include('elements/part_svc_column.html', + shift, + 'part_svc' => $part_svc, + 'clone' => $clone + ) + } +); </%init> diff --git a/httemplate/edit/part_tag.html b/httemplate/edit/part_tag.html index 5712560c1..2cf34c6e8 100644 --- a/httemplate/edit/part_tag.html +++ b/httemplate/edit/part_tag.html @@ -8,7 +8,7 @@ { field=>'by_default', type=>'checkbox', value=>'Y' }, $tagcolor, ], - 'labels' => { 'tagnum' => 'Tag #', + 'labels' => { 'tagnum' => 'Tag', 'tagname' => 'Tag', 'tagdesc' => 'Message', 'tagcolor' => 'Highlight Color', diff --git a/httemplate/edit/payment_gateway.html b/httemplate/edit/payment_gateway.html index dfe52f109..a469beb7f 100644 --- a/httemplate/edit/payment_gateway.html +++ b/httemplate/edit/payment_gateway.html @@ -19,7 +19,7 @@ <SCRIPT TYPE="text/javascript"> - var modulesForNamespace = <% to_json(\%modules_for_namespace, {canonical=>1}) %>; + var modulesForNamespace = <% encode_json(\%modules_for_namespace, {canonical=>1}) %>; function changeNamespace(what) { var ns = what.value; var select_module = document.getElementById('gateway_module'); diff --git a/httemplate/edit/phone_device.html b/httemplate/edit/phone_device.html index 4aec63e5a..7bc88a8c7 100644 --- a/httemplate/edit/phone_device.html +++ b/httemplate/edit/phone_device.html @@ -32,12 +32,11 @@ %> <%init> -my @deviceparts_with_inventory; -my @part_device = qsearch('part_device', {} ); -foreach my $part_device ( @part_device ) { - push @deviceparts_with_inventory, $part_device->devicepart - if $part_device->inventory_classnum; -} +my @deviceparts_with_inventory = + map $_->devicepart, + qsearch({ 'table' => 'part_device', + 'extra_sql' => 'WHERE inventory_classnum IS NOT NULL', + }); my $html_foot = sub { my $js = " @@ -72,9 +71,9 @@ my $html_foot = sub { var devicepart = what.options[what.selectedIndex].value; - var deviceparts_with_inventory = new Array(\""; -$js .= join("\",\"",@deviceparts_with_inventory); -$js .= "\"); + var deviceparts_with_inventory = new Array("; +$js .= join(',', map qq("$_"), @deviceparts_with_inventory); +$js .= "); var hasInventory = false; for ( i = 0; i < deviceparts_with_inventory.length; i++ ) { diff --git a/httemplate/edit/process/REAL_cust_pkg.cgi b/httemplate/edit/process/REAL_cust_pkg.cgi index 3e0ef59c1..fd2893487 100755 --- a/httemplate/edit/process/REAL_cust_pkg.cgi +++ b/httemplate/edit/process/REAL_cust_pkg.cgi @@ -19,36 +19,41 @@ die "access denied" my $pkgnum = $cgi->param('pkgnum') or die; my $old = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); my %hash = $old->hash; -$hash{$_}= $cgi->param($_) ? parse_datetime($cgi->param($_)) : '' - foreach qw( start_date setup bill last_bill contract_end ); +foreach ( qw( start_date setup bill last_bill contract_end ) ) { + if ( $cgi->param($_) =~ /^(\d+)$/ ) { + $hash{$_} = $1; + } else { + $hash{$_} = ''; + } # adjourn, expire, resume not editable this way - -my @errors = (); - -push @errors, '_bill_areyousure' - if $hash{'bill'} != $old->bill # if the next bill date was changed - && $hash{'bill'} < time # to a date in the past - && ! $cgi->param('bill_areyousure'); # and it wasn't confirmed - -push @errors, '_setup_areyousure' - if ! $hash{'setup'} && $old->setup # if the setup date was removed - && ! $cgi->param('setup_areyousure'); # and it wasn't confirmed - -push @errors, '_setupadd_areyousure' - if $hash{'setup'} && ! $old->setup # if the setup date was added - && ! $cgi->param('setupadd_areyousure'); # and it wasn't confirmed - -push @errors, '_start' - if $hash{'start_date'} && !$old->start_date # if a start date was added - && $hash{'setup'}; # but there's a setup date +} my $new; my $error; -if ( @errors ) { - $error = join(',', @errors); -} else { - $new = new FS::cust_pkg \%hash; - $error = $new->replace($old); +$new = new FS::cust_pkg \%hash; +$error = $new->replace($old); + +if (!$error) { + my @supp_pkgs = $old->supplemental_pkgs; + foreach $new (@supp_pkgs) { + foreach ( qw( start_date setup contract_end ) ) { + # propagate these to supplementals + $new->set($_, $hash{$_}); + } + if ( $hash{'bill'} ne $old->get('bill') ) { + if ( $hash{'bill'} and $old->get('bill') ) { + # adjust by the same interval + my $diff = $hash{'bill'} - $old->get('bill'); + $new->set('bill', $new->get('bill') + $diff); + } else { + # absolute date + $new->set('bill', $hash{'bill'}); + } + } + $error = $new->replace; + $error .= ' (supplemental package '.$new->pkgnum.')' if $error; + last if $error; + } } </%init> diff --git a/httemplate/edit/process/bulk-part_pkg.html b/httemplate/edit/process/bulk-part_pkg.html new file mode 100644 index 000000000..4775a9334 --- /dev/null +++ b/httemplate/edit/process/bulk-part_pkg.html @@ -0,0 +1,30 @@ +% if ( $error ) { +% $cgi->param('error', $error); +<% $cgi->redirect(popurl(3).'/edit/bulk-part_pkg.cgi?', $cgi->query_string) %> +% } else { +<% $cgi->redirect(popurl(3).'/browse/part_pkg.cgi') %> +% } +<%init> +die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Bulk edit package definitions'); + +my @pkgparts = $cgi->param('pkgpart') + or die "no package definitions selected"; + +my %changes; +foreach my $param (grep { /^report_option_\d+$/ } $cgi->param) { + if ( length($cgi->param($param)) ) { + if ( $cgi->param($param) == 1 ) { + $changes{$param} = 1; + } else { + $changes{$param} = ''; + } + } +} + +my $error; +foreach my $pkgpart (@pkgparts) { + my $part_pkg = FS::part_pkg->by_key($pkgpart); + my %options = ( $part_pkg->options, %changes ); + $error ||= $part_pkg->replace( options => \%options ); +} +</%init> diff --git a/httemplate/edit/process/change-cust_pkg.html b/httemplate/edit/process/change-cust_pkg.html index 2770f3283..77f261d56 100644 --- a/httemplate/edit/process/change-cust_pkg.html +++ b/httemplate/edit/process/change-cust_pkg.html @@ -32,11 +32,11 @@ my %change = map { $_ => scalar($cgi->param($_)) } $change{'keep_dates'} = 1; if ( $cgi->param('locationnum') == -1 ) { - my $cust_location = new FS::cust_location { + my $cust_location = FS::cust_location->new_or_existing({ 'custnum' => $cust_pkg->custnum, map { $_ => scalar($cgi->param($_)) } qw( address1 address2 city county state zip country ) - }; + }); $change{'cust_location'} = $cust_location; } diff --git a/httemplate/edit/process/credit-cust_bill_pkg.html b/httemplate/edit/process/credit-cust_bill_pkg.html index cbcf619ca..8e66368d4 100644 --- a/httemplate/edit/process/credit-cust_bill_pkg.html +++ b/httemplate/edit/process/credit-cust_bill_pkg.html @@ -10,7 +10,7 @@ <%init> die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Post credit'); + unless $FS::CurrentUser::CurrentUser->access_right('Credit line items'); my @billpkgnum_setuprecurs = map { $_ =~ /^billpkgnum(\d+\-\w*)$/ or die 'gm#23'; $1; } diff --git a/httemplate/edit/process/cust_location.cgi b/httemplate/edit/process/cust_location.cgi index b9f93db8b..56c3968f6 100644 --- a/httemplate/edit/process/cust_location.cgi +++ b/httemplate/edit/process/cust_location.cgi @@ -28,11 +28,10 @@ my $cust_location = qsearchs({ }); die "unknown locationnum $locationnum" unless $cust_location; -my $new = FS::cust_location->new({ +my $new = FS::cust_location->new_or_existing({ custnum => $cust_location->custnum, prospectnum => $cust_location->prospectnum, - map { $_ => scalar($cgi->param($_)) } - qw( address1 address2 city county state zip country ) + map { $_ => scalar($cgi->param($_)) } FS::cust_main->location_fields }); my $error = $cust_location->move_to($new); diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 31ec4ab12..c1f815550 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -16,8 +16,8 @@ my $DEBUG = 0; </%once> <%init> -die "access denied" - unless $FS::CurrentUser::CurrentUser->access_right('Edit customer'); +my $curuser = $FS::CurrentUser::CurrentUser; +die "access denied" unless $curuser->access_right('Edit customer'); my $conf = new FS::Conf; @@ -62,6 +62,18 @@ $cgi->param('invoicing_list', join(',', @invoicing_list) ); $cgi->param('duplicate_of_custnum') =~ /^(\d+)$/; my $duplicate_of = $1; +# if this is enabled, enforce it +if ( $conf->exists('agent-ship_address', $cgi->param('agentnum')) ) { + my $agent = FS::agent->by_key($cgi->param('agentnum')); + my $agent_cust_main = $agent->agent_cust_main; + if ( $agent_cust_main ) { + my $agent_location = $agent_cust_main->ship_location; + foreach (qw(address1 city state zip country latitude longitude district)) { + $cgi->param("ship_$_", $agent_location->get($_)); + } + } +} + my %locations; for my $pre (qw(bill ship)) { @@ -71,10 +83,7 @@ for my $pre (qw(bill ship)) { } $hash{'custnum'} = $cgi->param('custnum'); warn Dumper \%hash if $DEBUG; - # if we can qsearchs it, then it's unchanged, so use that - $locations{$pre} = qsearchs('cust_location', \%hash) - || FS::cust_location->new( \%hash ); - + $locations{$pre} = FS::cust_location->new_or_existing(\%hash); } if ( ($cgi->param('same') || '') eq 'Y' ) { @@ -156,9 +165,14 @@ foreach my $dfield (qw( $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; -my %tax_exempt = map { $_ => scalar($cgi->param("tax_$_".'_num')) } @tax_exempt; +my %options = (); +if ( $curuser->access_right('Edit customer tax exemptions') ) { + my @exempt_groups = grep /\S/, $conf->config('tax-cust_exempt-groups'); + my @tax_exempt = grep { $cgi->param("tax_$_") eq 'Y' } @exempt_groups; + $options{'tax_exemption'} = { + map { $_ => scalar($cgi->param("tax_$_".'_num')) } @tax_exempt + }; +} #perhaps this stuff should go to cust_main.pm if ( $new->custnum eq '' or $duplicate_of ) { @@ -266,8 +280,8 @@ if ( $new->custnum eq '' or $duplicate_of ) { else { # create the customer $error ||= $new->insert( \%hash, \@invoicing_list, - 'tax_exemption'=> \%tax_exempt, - 'prospectnum' => scalar($cgi->param('prospectnum')), + %options, + prospectnum => scalar($cgi->param('prospectnum')), ); my $conf = new FS::Conf; @@ -328,7 +342,7 @@ if ( $new->custnum eq '' or $duplicate_of ) { warn Dumper({ new => $new, old => $old }) if $DEBUG; $error ||= $new->replace( $old, \@invoicing_list, - 'tax_exemption' => \%tax_exempt, + %options, ); warn "$me returned from replace" if $DEBUG; diff --git a/httemplate/edit/process/cust_pkg_quantity.html b/httemplate/edit/process/cust_pkg_quantity.html new file mode 100644 index 000000000..fb2657252 --- /dev/null +++ b/httemplate/edit/process/cust_pkg_quantity.html @@ -0,0 +1,33 @@ +% if ($error) { +% $cgi->param('error', $error); +% $cgi->redirect(popurl(3). 'edit/cust_pkg_quantity.html?'. $cgi->query_string ); +% } else { + + <& /elements/header-popup.html, "Quantity changed" &> + <SCRIPT TYPE="text/javascript"> + window.top.location.reload(); + </SCRIPT> + </BODY> + </HTML> + +% } +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('Change customer package'); + +my $cust_pkg = qsearchs({ + 'table' => 'cust_pkg', + 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', + 'hashref' => { 'pkgnum' => scalar($cgi->param('pkgnum')), }, + 'extra_sql' => ' AND '. $curuser->agentnums_sql, +}); +die 'unknown pkgnum' unless $cust_pkg; + +$cgi->param('quantity') =~ /^(\d+)$/; +my $quantity = $1; +my $error = $cust_pkg->set_quantity($1); + +</%init> diff --git a/httemplate/edit/process/cust_svc.cgi b/httemplate/edit/process/cust_svc.cgi index e22cbb201..7cb1d6d8f 100644 --- a/httemplate/edit/process/cust_svc.cgi +++ b/httemplate/edit/process/cust_svc.cgi @@ -6,7 +6,7 @@ %} <%init> -die 'access deined' +die 'access denied' unless $FS::CurrentUser::CurrentUser->access_right('Change customer service'); my $svcnum = $cgi->param('svcnum'); diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html index 2d39e9dce..fb1ee7a27 100644 --- a/httemplate/edit/process/elements/process.html +++ b/httemplate/edit/process/elements/process.html @@ -263,6 +263,9 @@ foreach my $value ( @values ) { if ( !$error ) { if ( $old_pkey ) { + + &{ $opt{'edit_callback'} }( $new, $old ) if $opt{'edit_callback'}; + $error = $new->replace($old, @args); } else { $error = $new->insert(@args); diff --git a/httemplate/edit/process/elements/svc_Common.html b/httemplate/edit/process/elements/svc_Common.html index 5a8afbd6c..06f4c00b1 100644 --- a/httemplate/edit/process/elements/svc_Common.html +++ b/httemplate/edit/process/elements/svc_Common.html @@ -10,5 +10,10 @@ my %opt = @_; my $table = $opt{'table'}; $opt{'fields'} ||= [ fields($table) ]; push @{ $opt{'fields'} }, qw( pkgnum svcpart ); +foreach (fields($table)) { + if ( $cgi->param($_.'_classnum') ) { + push @{ $opt{'fields'} }, $_.'_classnum'; + } +} </%init> diff --git a/httemplate/edit/process/part_export.cgi b/httemplate/edit/process/part_export.cgi index bcb9c0df1..e0c470675 100644 --- a/httemplate/edit/process/part_export.cgi +++ b/httemplate/edit/process/part_export.cgi @@ -56,6 +56,7 @@ my $new = new FS::part_export ( { if ( $cgi->param('svc_machine') eq 'Y' ) { $new->machine('_SVC_MACHINE'); $new->part_export_machine_textarea( $cgi->param('part_export_machine') ); + $new->default_machine_name( $cgi->param('default_machine_name') ); } my $error; diff --git a/httemplate/edit/process/part_pkg.cgi b/httemplate/edit/process/part_pkg.cgi index c388676df..932e33b1d 100755 --- a/httemplate/edit/process/part_pkg.cgi +++ b/httemplate/edit/process/part_pkg.cgi @@ -10,6 +10,7 @@ 'precheck_callback' => $precheck_callback, 'args_callback' => $args_callback, 'process_m2m' => \@process_m2m, + 'process_o2m' => \@process_o2m, ) %> <%init> @@ -185,6 +186,15 @@ my @process_m2m = ( grep /^svc_dst_pkgpart/, $cgi->param ], }, + { 'link_table' => 'part_pkg_link', + 'target_table' => 'part_pkg', + 'base_field' => 'src_pkgpart', + 'target_field' => 'dst_pkgpart', + 'hashref' => { 'link_type' => 'supp', 'hidden' => '' }, + 'params' => [ map $cgi->param($_), + grep /^supp_dst_pkgpart/, $cgi->param + ], + }, map { my $hidden = $_; { 'link_table' => 'part_pkg_link', @@ -235,4 +245,11 @@ if ( $cgi->param('pkgpart') || ! $conf->exists('agent_defaultpkg') ) { }; } +my @process_o2m = ( + { + 'table' => 'part_pkg_msgcat', + 'fields' => [qw( locale pkg )], + }, +); + </%init> diff --git a/httemplate/edit/process/part_pkg_usage.html b/httemplate/edit/process/part_pkg_usage.html new file mode 100644 index 000000000..eb6c37b82 --- /dev/null +++ b/httemplate/edit/process/part_pkg_usage.html @@ -0,0 +1,67 @@ +% if ( $is_error ) { +% $cgi->param('error' => \%part_pkg_usage); +% # internal redirect, because it's a lot of state to pass through +<& /browse/part_pkg_usage.html &> +% } else { +% # uh, not quite sure... +<% $cgi->redirect($fsurl.'browse/part_pkg.cgi') %> +% } +<%init> +my %vars = $cgi->Vars; +my %part_pkg_usage; +my $is_error; +foreach my $pkgpart ($cgi->param('pkgpart')) { + next unless $pkgpart =~ /^\d+$/; + my $part_pkg = FS::part_pkg->by_key($pkgpart) + or die "unknown pkgpart $pkgpart"; + my %old = map { $_->pkgusagepart => $_ } $part_pkg->part_pkg_usage; + $part_pkg_usage{$pkgpart} ||= []; + my @rows; + foreach (grep /^pkgpart$pkgpart/, keys %vars) { + /^pkgpart\d+_(\w+\D)(\d+)$/ or die "misspelled field name '$_'"; + my $value = delete $vars{$_}; + my $field = $1; + my $row = $2; + $rows[$row] ||= {}; + $rows[$row]->{$field} = $value; + } + + foreach my $row (@rows) { + next if !defined($row); + my $error; + my %classes; + foreach my $class (grep /^class/, keys %$row) { + $class =~ /^class(\d+)_$/; + my $classnum = $1; + $classes{$classnum} = delete $row->{$class}; + } + my $usage = FS::part_pkg_usage->new($row); + $usage->set('pkgpart', $pkgpart); + if ( $usage->pkgusagepart and $row->{minutes} > 0 ) { + $error = $usage->replace(\%classes); + # and don't delete the existing one + delete($old{$usage->pkgusagepart}); + } elsif ( $row->{minutes} > 0 ) { + $error = $usage->insert(\%classes); + } else { + next; + } + if ( $error ) { + $usage->set('error', $error); + $is_error = 1; + } + push @{ $part_pkg_usage{$pkgpart} }, $usage; + } + + foreach my $usage (values %old) { + # all of these were not sent back by the client, so delete them + my $error = $usage->delete; + if ( $error ) { + $usage->set('error', $error); + $is_error = 1; + unshift @{ $part_pkg_usage{$pkgpart} }, $usage; + } + } + +} +</%init> diff --git a/httemplate/edit/process/quick-cust_pkg.cgi b/httemplate/edit/process/quick-cust_pkg.cgi index 2dadbccdc..0cc17d36b 100644 --- a/httemplate/edit/process/quick-cust_pkg.cgi +++ b/httemplate/edit/process/quick-cust_pkg.cgi @@ -70,6 +70,9 @@ my $quantity = $1 || 1; $cgi->param('refnum') =~ /^(\d*)$/ or die 'illegal refnum '. $cgi->param('refnum'); my $refnum = $1; +$cgi->param('contactnum') =~ /^(\-?\d*)$/ + or die 'illegal contactnum '. $cgi->param('contactnum'); +my $contactnum = $1; $cgi->param('locationnum') =~ /^(\-?\d*)$/ or die 'illegal locationnum '. $cgi->param('locationnum'); my $locationnum = $1; @@ -109,6 +112,7 @@ my %hash = ( : '' ), 'refnum' => $refnum, + 'contactnum' => $contactnum, 'locationnum' => $locationnum, 'discountnum' => $discountnum, #for the create a new discount case @@ -142,11 +146,19 @@ if ( $quotationnum ) { my %opt = ( 'cust_pkg' => $cust_pkg ); + if ( $contactnum == -1 ) { + my $contact = FS::contact->new({ + 'custnum' => scalar($cgi->param('custnum')), + map { $_ => scalar($cgi->param("contactnum_$_")) } qw( first last ) + }); + $opt{'contact'} = $contact; + } + if ( $locationnum == -1 ) { - my $cust_location = new FS::cust_location { + my $cust_location = FS::cust_location->new_or_existing({ map { $_ => scalar($cgi->param($_)) } - qw( custnum address1 address2 city county state zip country geocode ) - }; + ('custnum', FS::cust_main->location_fields) + }); $opt{'cust_location'} = $cust_location; } diff --git a/httemplate/edit/process/svc_phone.html b/httemplate/edit/process/svc_phone.html index 7a3b43d32..9983ea2cb 100644 --- a/httemplate/edit/process/svc_phone.html +++ b/httemplate/edit/process/svc_phone.html @@ -2,6 +2,7 @@ 'table' => 'svc_phone', 'args_callback' => $args_callback, 'value_callback' => $value_callback, + 'edit_callback' => $edit_callback, %opt, &> <%init> @@ -28,6 +29,9 @@ my $right = $opt{'bulk'} ? 'Bulk provision customer service' die "access denied" unless $FS::CurrentUser::CurrentUser->access_right($right); +$cgi->param('phonenum', $cgi->param('phonenum_manual') ) + if $cgi->param('phonenum_which') eq 'phonenum_manual'; + my $tollfreephonenum = $cgi->param('tollfreephonenum'); $cgi->param('phonenum',$tollfreephonenum) if $tollfreephonenum =~ /^\d+$/; @@ -36,10 +40,10 @@ my $args_callback = sub { my %opt = (); if ( $cgi->param('locationnum') == -1 ) { - my $cust_location = new FS::cust_location { + my $cust_location = FS::cust_location->new_or_existing({ map { $_ => scalar($cgi->param($_)) } qw( custnum address1 address2 city county state zip country ) - }; + }); $opt{'cust_location'} = $cust_location; } @@ -48,8 +52,13 @@ my $args_callback = sub { }; my $value_callback = sub { - my ($field, $value) = @_; - ($field =~ /_date$/) ? parse_datetime($value) : $value; + my ($field, $value) = @_; + ($field =~ /_date$/) ? parse_datetime($value) : $value; +}; + +my $edit_callback = sub { + my( $new, $old ) = @_; + $new->sip_password( $old->sip_password ) if $new->sip_password eq '*HIDDEN*'; }; </%init> diff --git a/httemplate/edit/quick-charge.html b/httemplate/edit/quick-charge.html index 1d9647f2f..466091dfa 100644 --- a/httemplate/edit/quick-charge.html +++ b/httemplate/edit/quick-charge.html @@ -145,7 +145,6 @@ function bill_now_changed (what) { <% mt('with terms') |h %> <& /elements/select-terms.html, 'curr_value' => scalar($cgi->param('invoice_terms')), - 'empty_value' => $default_terms, 'disabled' => ( $cgi->param('bill_now') ? 0 : 1 ), &> </TD> diff --git a/httemplate/edit/rate_region.cgi b/httemplate/edit/rate_region.cgi index 367bbafb6..a1c1bcb7d 100644 --- a/httemplate/edit/rate_region.cgi +++ b/httemplate/edit/rate_region.cgi @@ -33,6 +33,14 @@ </TD> </TR> + <& /elements/tr-checkbox.html, + label => 'Exact match', + field => 'exact_match', + cell_style => 'font-weight: bold', + value => 'Y', + curr_value => $rate_region->exact_match + &> + </TABLE> <BR> diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi index c1f74551d..627791ba7 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -9,19 +9,6 @@ <BR> % } -<SCRIPT TYPE="text/javascript"> -function randomPass() { - var i=0; - var pw_set='<% join('', 'a'..'z', 'A'..'Z', '0'..'9' ) %>'; - var pass=''; - while(i < 8) { - i++; - pass += pw_set.charAt(Math.floor(Math.random() * pw_set.length)); - } - document.OneTrueForm.clear_password.value = pass; -} -</SCRIPT> - <FORM NAME="OneTrueForm" ACTION="<% $p1 %>process/svc_acct.cgi" METHOD=POST> <INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>"> <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> @@ -57,10 +44,11 @@ function randomPass() { %if ( $part_svc->part_svc_column('_password')->columnflag ne 'F' ) { <TR> +% #XXX eventually should require "Edit Password" ACL <TD ALIGN="right"><% mt('Password') |h %></TD> <TD> - <INPUT TYPE="text" NAME="clear_password" VALUE="<% $password %>" SIZE=<% $pmax2 %> MAXLENGTH=<% $pmax %>> - <INPUT TYPE="button" VALUE="<% mt('Generate') |h %>" onclick="randomPass();"> + <INPUT TYPE="text" ID="clear_password" NAME="clear_password" VALUE="<% $password %>" SIZE=<% $pmax2 %> MAXLENGTH=<% $pmax %>> + <& /elements/random_pass.html, 'clear_password' &> </TD> </TR> %}else{ diff --git a/httemplate/edit/svc_broadband.cgi b/httemplate/edit/svc_broadband.cgi index 0d4b9897b..1b85460e6 100644 --- a/httemplate/edit/svc_broadband.cgi +++ b/httemplate/edit/svc_broadband.cgi @@ -104,8 +104,12 @@ my @fields = ( { field=>'sectornum', type=>'select-tower_sector', }, { field=>'routernum', type=>'select-router_block_ip' }, { field=>'mac_addr' , type=>'input-mac_addr' }, - qw( latitude longitude altitude vlan_profile - performance_profile authkey plan_id ) + qw( + latitude longitude altitude + radio_serialnum radio_location poe_location rssi suid + ), + { field=>'shared_svcnum', type=>'search-svc_broadband', }, + qw( vlan_profile performance_profile authkey plan_id ), ); if ( $conf->exists('svc_broadband-radius') ) { diff --git a/httemplate/edit/svc_phone.cgi b/httemplate/edit/svc_phone.cgi index 9647b6887..13bbe82a1 100644 --- a/httemplate/edit/svc_phone.cgi +++ b/httemplate/edit/svc_phone.cgi @@ -6,6 +6,11 @@ my( $cgi, $svc_x, $part_svc, $cust_pkg, $fields, $opt ) = @_; $svc_x->locationnum($cust_pkg->locationnum) if $cust_pkg; }, + 'svc_edit_callback' => sub { + my( $cgi, $svc_x, $part_svc, $cust_pkg, $fields, $opt) = @_; + my $conf = new FS::Conf; + $svc_x->sip_password('*HIDDEN*') unless $conf->exists('showpasswords'); + }, &> <%init> @@ -28,6 +33,11 @@ my $begin_callback = sub { type => 'select-did', label => 'Phone number', multiple => $bulk, + }, + { field => 'sim_imsi', + type => 'text', + size => 15, + maxlength => 15, }; push @$fields, { field => 'domsvc', |