diff options
Diffstat (limited to 'httemplate/misc')
31 files changed, 898 insertions, 167 deletions
diff --git a/httemplate/misc/batch-cust_pay.html b/httemplate/misc/batch-cust_pay.html index 505f2d0..610f6e1 100644 --- a/httemplate/misc/batch-cust_pay.html +++ b/httemplate/misc/batch-cust_pay.html @@ -13,23 +13,63 @@ function warnUnload() { } } window.onbeforeunload = warnUnload; + +function select_discount_term(row, prefix) { + var custnum_obj = document.getElementById('custnum'+prefix+row); + var select_obj = document.getElementById('discount_term'+prefix+row); + + var value = ''; + if (select_obj.type == 'hidden') { + value = select_obj.value; + } + + var term_select = document.createElement('SELECT'); + term_select.setAttribute('name', 'discount_term'+row); + term_select.setAttribute('id', 'discount_term'+row); + term_select.setAttribute('rownum', row); + term_select.style.display = ''; + select_obj.parentNode.replaceChild(term_select, select_obj); + opt(term_select, '', '1 month'); + + function select_discount_term_update(discount_terms) { + + var termArray = eval('(' + discount_terms + ')'); + for ( var t = 0; t < termArray.length; t++ ) { + opt(term_select, termArray[t][0], termArray[t][1]); + if (termArray[t][0] == value) { + term_select.selectedIndex = t+1; + } + } + + } + + discount_terms(custnum_obj.value, select_discount_term_update); + +} </SCRIPT> +<% include('/elements/xmlhttp.html', + 'url' => $p. 'misc/xmlhttp-cust_main-discount_terms.cgi', + 'subs' => [qw( discount_terms )], + ) +%> + <FORM ACTION="process/batch-cust_pay.cgi" NAME="OneTrueForm" METHOD="POST" onsubmit="document.OneTrueForm.submit.disabled=true;window.onbeforeunload = null;"> <!-- <B>Batch</B> <INPUT TYPE="text" NAME="paybatch"><BR><BR> --> <% include( "/elements/customer-table.html", name_singular => 'payment', - header => [ '', 'Amount', 'Check #', '' ], - fields => [ sub {'$'}, 'paid', 'payinfo', 'error', ], - types => [ 'immutable', '', '', 'immutable', ], - align => [ 'c', 'r', 'r', 'l' ], - sizes => [ 0, 8, 10, 0, ], - colors => [ '', '', '', '#ff0000' ], - param => { () }, - footer => [ '$', '_TOTAL', '', '' ], - footer_align => [ 'c', 'r', 'r', '' ], + header => \@header, + fields => \@fields, + types => \@types, + align => \@align, + sizes => \@sizes, + colors => \@colors, + param => \%param, + footer => \@footer, + footer_align => \@footer_align, + custnum_update_callback => $custnum_update_callback, ) %> @@ -41,6 +81,14 @@ window.onbeforeunload = warnUnload; </FORM> +%if ( $cgi->param('error') ) { +<SCRIPT TYPE="text/javascript"> +% for ( my $row = 0; defined($cgi->param("custnum$row")); $row++ ) { + select_discount_term(<% $row %>, ''); +% } +</SCRIPT> +%} + <% include('/elements/footer.html') %> <%init> @@ -48,4 +96,36 @@ window.onbeforeunload = warnUnload; die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Post payment batch'); +my @header = ( '', 'Amount', 'Check #' ); +my @fields = ( sub {'$'}, 'paid', 'payinfo' ); +my @types = ( 'immutable', '', '' ); +my @align = ( 'c', 'r', 'r' ); +my @sizes = ( 0, 8, 10 ); +my @colors = ( '', '', '' ); +my %param = (); +my @footer = ( '$', '_TOTAL', '' ); +my @footer_align = ( 'c', 'r', 'r' ); +my $custnum_update_callback = ''; + +if ( FS::Record->scalar_sql('SELECT count(*) FROM part_pkg_discount') ) { + push @header, ''; + push @fields, 'discount_term'; + push @types, 'immutable'; + push @align, 'r'; + push @sizes, '0'; + push @colors, ''; + push @footer, ''; + push @footer_align, ''; + $custnum_update_callback = 'select_discount_term'; +} + +push @header, ''; +push @fields, 'error'; +push @types, 'immutable'; +push @align, 'l'; +push @sizes, '0'; +push @colors, '#ff0000'; +push @footer, ''; +push @footer_align, ''; + </%init> diff --git a/httemplate/misc/cancel_cust.html b/httemplate/misc/cancel_cust.html index 12c37eb..b7ecccd 100644 --- a/httemplate/misc/cancel_cust.html +++ b/httemplate/misc/cancel_cust.html @@ -2,18 +2,46 @@ <% include('/elements/error.html') %> + <FORM NAME="cust_cancel_popup" ACTION="<% popurl(1) %>cust_main-cancel.cgi" METHOD=POST> <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> <P ALIGN="center"><B>Permanently delete all services and cancel this customer?</B> - <% $ban %> - -<BR><BR> - -<% ntable("#cccccc", 2) %> +<TABLE BORDER="0" CELLSPACING="2" +STYLE="margin-left:auto; margin-right:auto"> +<TR> + <TD ALIGN="right"> + <INPUT TYPE="radio" NAME="now_or_later" VALUE="0" onclick="toggle(false)" CHECKED /> + </TD> + <TD ALIGN="left">Cancel now</TD> +</TR> +<TR> + <TD ALIGN="right"> + <INPUT TYPE="radio" NAME="now_or_later" VALUE="1" onclick="toggle(true)" /> + </TD> + <TD ALIGN="left">Cancel on date: + <% include('/elements/input-date-field.html', { + 'name' => 'expire', + 'value' => time, + } ) %> + </TD> +</TR> +</TABLE> +<SCRIPT type="text/javascript"> +function toggle(val) { + document.getElementById("expire_text").disabled = !val; + document.getElementById("ban").disabled = val; + document.getElementById("expire_button").style.visibility = + val ? 'visible' : 'hidden'; +} +toggle(false); +</SCRIPT> +<% $ban %> +<TABLE BGCOLOR="#cccccc", BORDER="0" CELLSPACING="2" +STYLE="margin-left:auto; margin-right:auto"> <% include('/elements/tr-select-reason.html', 'field' => 'reasonnum', 'reason_class' => 'C', @@ -50,8 +78,8 @@ die "No customer # $custnum" unless $cust_main; my $ban = ''; if ( $cust_main->payby =~ /^(CARD|DCRD|CHEK|DCHK)$/ ) { - $ban = '<BR><P ALIGN="center">'. - '<INPUT TYPE="checkbox" NAME="ban" VALUE="1"> Ban this customer\'s '; + $ban = '<P ALIGN="center">'. + '<INPUT TYPE="checkbox" NAME="ban" ID="ban" VALUE="1"> Ban this customer\'s '; if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) { $ban .= 'credit card'; } elsif ( $cust_main->payby =~ /^(CHEK|DCHK)$/ ) { diff --git a/httemplate/misc/change_pkg.cgi b/httemplate/misc/change_pkg.cgi index 16b7071..ec10b85 100755 --- a/httemplate/misc/change_pkg.cgi +++ b/httemplate/misc/change_pkg.cgi @@ -2,7 +2,7 @@ <% include('/elements/error.html') %> -<FORM ACTION="<% $p %>edit/process/change-cust_pkg.html" METHOD=POST> +<FORM NAME="OrderPkgForm" ACTION="<% $p %>edit/process/change-cust_pkg.html" METHOD=POST> <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>"> <% ntable('#cccccc') %> @@ -31,8 +31,16 @@ </TABLE> +<% include( '/elements/standardize_locations.html', + 'form' => "OrderPkgForm", + 'onlyship' => 1, + 'no_company' => 1, + 'callback' => 'document.OrderPkgForm.submit();', + ) +%> + <BR> -<INPUT TYPE="submit" VALUE="Change package"> +<INPUT NAME="submitButton" TYPE="button" VALUE="Change package" onClick="this.disabled=true; standardize_locations();"> </FORM> </BODY> diff --git a/httemplate/misc/choose_tax_location.html b/httemplate/misc/choose_tax_location.html new file mode 100644 index 0000000..dce04c7 --- /dev/null +++ b/httemplate/misc/choose_tax_location.html @@ -0,0 +1,90 @@ +<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.<% $formname %>.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($formname) = $cgi->param('formname') =~ /^([\w]*)$/; +$formname ||= 'CustomerForm'; + +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/misc/cust_main-cancel.cgi b/httemplate/misc/cust_main-cancel.cgi index 009a7d4..44be20c 100755 --- a/httemplate/misc/cust_main-cancel.cgi +++ b/httemplate/misc/cust_main-cancel.cgi @@ -1,4 +1,4 @@ -<% header("Customer cancelled") %> +<% include('/elements/header.html', "Customer cancelled") %> <SCRIPT TYPE="text/javascript"> window.top.location.reload(); </SCRIPT> @@ -11,9 +11,11 @@ die "access denied" my $custnum; my $ban = ''; +my $expire = ''; if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { $custnum = $1; $ban = $cgi->param('ban'); + $expire = $cgi->param('expire'); } else { my($query) = $cgi->keywords; $query =~ /^(\d+)$/ || die "Illegal custnum"; @@ -42,11 +44,28 @@ my $cust_main = qsearchs( { 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, } ); -warn "cancelling $cust_main"; -my @errors = $cust_main->cancel( - 'ban' => $ban, - 'reason' => $reasonnum, -); +my @errors; +if($cgi->param('now_or_later')) { + $expire = parse_datetime($expire); + if($expire) { + #warn "setting expire dates on custnum#$custnum\n"; + my @pkgs = $cust_main->ncancelled_pkgs; + @errors = grep {$_} map { $_->cancel( + 'reason' => $reasonnum, + 'date' => $expire, + ) } @pkgs; + } + else { + @errors = ("error parsing expire date: ".$cgi->param('expire')); + } +} +else { + warn "cancelling $cust_main"; + @errors = $cust_main->cancel( + 'ban' => $ban, + 'reason' => $reasonnum, + ); +} my $error = join(' / ', @errors) if scalar(@errors); if ( $error ) { diff --git a/httemplate/misc/cust_main-import.cgi b/httemplate/misc/cust_main-import.cgi index 9c1f984..edf4665 100644 --- a/httemplate/misc/cust_main-import.cgi +++ b/httemplate/misc/cust_main-import.cgi @@ -30,7 +30,9 @@ Import a file containing customer records. <SELECT NAME="format"> <!-- <OPTION VALUE="simple">Simple --> <OPTION VALUE="extended" SELECTED>Extended + <OPTION VALUE="extended-plus_options">Extended + options <OPTION VALUE="extended-plus_company">Extended plus company + <OPTION VALUE="extended-plus_company_and_options">Extended plus company and options <OPTION VALUE="svc_external">External service <OPTION VALUE="svc_external_svc_phone">External service and phone service </SELECT> @@ -89,7 +91,11 @@ Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets. <b>Extended</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, username, _password</i> <BR><BR> +<b>Extended plus options</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, username, _password, options</i> + <b>Extended plus company</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, company, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_company, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, username, _password</i> + +<b>Extended plus company and options </b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, company, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_company, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, username, _password, options</i> <BR><BR> <b>External service</b> format has the following field order: <i>agent_custid, refnum<%$req%>, last<%$req%>, first<%$req%>, company, address1<%$req%>, address2, city<%$req%>, state<%$req%>, zip<%$req%>, country, daytime, night, ship_last, ship_first, ship_company, ship_address1, ship_address2, ship_city, ship_state, ship_zip, ship_country, payinfo, paycvv, paydate, invoicing_list, pkgpart, next_bill_date, id, title</i> @@ -111,7 +117,7 @@ Field information: of an integer, the string is searched for and if necessary auto-created in the advertising source table. - <li><i>payinfo</i>: Credit card number, or leave this, <i>paycvv</i> and <i>paydate</i> blank for email/paper invoicing. + <li><i>payinfo</i>: Credit card number, or leave this, <i>paycvv</i> and <i>paydate</i> blank for email/paper invoicing. You may optionally prepend an 'A' or 'D' to the credit card number for automatic or on demand of customer billing respectively <li><i>paycvv</i>: CVV2 number (three digits on the back of the credit card) @@ -119,7 +125,7 @@ advertising source table. <li><i>invoicing_list</i>: Email address for invoices, or POST for postal invoices. - <li><i>pkgpart</i>: Package definition. Configuration -> Provisioning, services and packages -> View/Edit package definitions + <li><i>pkgpart</i>: Package definition. Configuration -> Packages -> Package definitions <li><i>username</i> and <i>_password</i> are required if <i>pkgpart</i> is specified. (Extended and Extended plus company formats) @@ -127,6 +133,13 @@ advertising source table. <li><i>title</i>: External service identifier, text + <li><i>options</i>: text containing one or more of + + <ul> + <li>taxexempt: this customer does not pay taxes + <li>postalinvoice: ensure this customer receives a postal invoice + </ul> + </ul> <BR> diff --git a/httemplate/misc/cust_main-import_charges.cgi b/httemplate/misc/cust_main-import_charges.cgi index 3801929..c844e0e 100644 --- a/httemplate/misc/cust_main-import_charges.cgi +++ b/httemplate/misc/cust_main-import_charges.cgi @@ -1,22 +1,69 @@ -<% include('/elements/header.html', 'Batch Customer Charge') %> +<% include("/elements/header.html",'Batch Payment Charge') %> + +Import a CSV file containing customer payments. +<BR><BR> <FORM ACTION="process/cust_main-import_charges.cgi" METHOD="post" ENCTYPE="multipart/form-data"> -Import a CSV file containing customer charges.<BR><BR> -Default file format is CSV, with the following field order: <i>custnum, amount, description</i><BR><BR> -If <i>amount</i> is negative, a credit will be applied instead.<BR><BR> -<BR><BR> +<% &ntable("#cccccc", 2) %> + +<% include('/elements/tr-select-agent.html', + #'curr_value' => '', #$agentnum, + 'label' => "<B>Agent</B>", + 'empty_label' => 'Select agent', + ) +%> + +<TR> + <TH ALIGN="right">Format</TH> + <TD> + <SELECT NAME="format"> + <OPTION VALUE="simple">Simple +<!-- <OPTION VALUE="extended" SELECTED>Extended --> + </SELECT> + </TD> +</TR> + +<TR> + <TH ALIGN="right">CSV filename</TH> + <TD><INPUT TYPE="file" NAME="csvfile"></TD> +</TR> -CSV Filename: <INPUT TYPE="file" NAME="csvfile"><BR><BR> -<INPUT TYPE="submit" VALUE="Import"> +<TR><TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px"><INPUT TYPE="submit" VALUE="Import CSV file"></TD></TR> + +</TABLE> </FORM> -<% include('/elements/footer.html') %> +<BR> + +Simple file format is CSV, with the following field order: <i>custnum, agent_custid, amount, description</i> +<BR><BR> + +<!-- Extended file format is not yet defined</i> +<BR><BR> --> +Field information: + +<ul> + + <li><i>custnum</i>: This is the freeside customer number. It may be left blank. If specified, agent_custid must be blank. + + <li><i>agent_custid</i>: This is the reseller's idea of the customer number or identifier. It may be left blank. If specified, custnum must be blank. + + <li><i>amount</i>: A numeric value with at most two digits after the decimal point. If <i>amount</i> is negative, a credit will be applied instead. + + <li><i>description</i>: Text describing the transaction. + +</ul> + +<BR> + +<% include('/elements/footer.html') %> <%init> die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Import'); </%init> + diff --git a/httemplate/misc/cust_main-merge.html b/httemplate/misc/cust_main-merge.html new file mode 100755 index 0000000..4decbef --- /dev/null +++ b/httemplate/misc/cust_main-merge.html @@ -0,0 +1,40 @@ +% if ( $error ) { +% $cgi->param('error', $error); +<% $cgi->redirect(popurl(1). "merge_cust.html?". $cgi->query_string ) %> +% } else { +<% include('/elements/header-popup.html', "Customer merged") %> + <SCRIPT TYPE="text/javascript"> + window.top.location.href = '<% $p %>view/cust_main.cgi?<% $new_custnum %>'; +%# parent.nd(1) ? + </SCRIPT> + </BODY> +</HTML> +% } +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Merge customer'); + +my $error = ''; + +$cgi->param('custnum') =~ /^(\d+)$/ or die "illegal custnum"; +my $custnum = $1; + +my $new_custnum; +if ( $cgi->param('new_custnum') =~ /^(\d+)$/ ) { + $new_custnum = $1; + + my $cust_main = qsearchs( { + 'table' => 'cust_main', + 'hashref' => { 'custnum' => $custnum }, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, + } ); + die "No customer # $custnum" unless $cust_main; + + $error = $cust_main->merge($new_custnum); + +} else { + $error = 'Select a customer to merge into'; +} + +</%init> diff --git a/httemplate/misc/cust_main_note-import.cgi b/httemplate/misc/cust_main_note-import.cgi index b93c5c1..8a94ae4 100644 --- a/httemplate/misc/cust_main_note-import.cgi +++ b/httemplate/misc/cust_main_note-import.cgi @@ -108,6 +108,7 @@ % my $fh = $cgi->upload('csvfile'); % my $csv = new Text::CSV_XS; % my $skip_fuzzies = $cgi->param('fuzzies') ? 0 : 1; +% my $use_agent_custid = $cgi->param('use_agent_custid') ? 1 : 0; % % if ( defined($fh) ) { <TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0> @@ -118,7 +119,7 @@ <TH>First</TH> <TH>Note to be added</TH> </TR> -% my $agentnum => scalar($cgi->param('agentnum')), +% my $agentnum = scalar($cgi->param('agentnum')); % my $line; % my $row = 0; % while ( defined($line=<$fh>) ) { @@ -138,7 +139,10 @@ % next unless ( $last || $first || $note ); % my @cust_main = (); % warn "searching for: $last, $first" if ($first || $last); -% if ($custnum) { +% if ($agentnum && $custnum && $use_agent_custid) { +% @cust_main = qsearch('cust_main', { 'agent' => $agentnum, +% 'agent_custid' => $custnum } ); +% } elsif ($custnum) { # && !use_agent_custid % @cust_main = qsearch('cust_main', { 'custnum' => $custnum }); % } else { % @cust_main = FS::cust_main::smart_search( diff --git a/httemplate/misc/cust_main_note-import.html b/httemplate/misc/cust_main_note-import.html index d8fefa7..cc1645d 100644 --- a/httemplate/misc/cust_main_note-import.html +++ b/httemplate/misc/cust_main_note-import.html @@ -13,6 +13,13 @@ Anything after the character sequence #! is ignored. <% &ntable("#cccccc") %> +<% include('/elements/tr-select-agent.html', + #'curr_value' => '', #$agentnum, + 'label' => "<B>Agent</B>", + 'empty_label' => 'Select agent', + ) +%> + <TR> <TH ALIGN="right">CSV filename</TH> <TD><INPUT TYPE="file" NAME="csvfile"></TD> @@ -22,6 +29,11 @@ Anything after the character sequence #! is ignored. <TD><INPUT TYPE="checkbox" NAME="fuzzies"></TD> </TR> +<TR> + <TH ALIGN="right">custnum is reseller's customer number</TH> + <TD><INPUT TYPE="checkbox" NAME="use_agent_custid"></TD> +</TR> + </TABLE> <BR><BR> diff --git a/httemplate/misc/cust_pkg-import.html b/httemplate/misc/cust_pkg-import.html new file mode 100644 index 0000000..b29884d --- /dev/null +++ b/httemplate/misc/cust_pkg-import.html @@ -0,0 +1,150 @@ +<% include("/elements/header.html",'Batch Package Import') %> + +Import a file containing package records. +<BR><BR> + +<% include( '/elements/form-file_upload.html', + 'name' => 'PackageImportForm', + 'action' => 'process/cust_pkg-import.html', + 'num_files' => 1, + 'fields' => [ 'agentnum', 'pkgbatch', 'format' ], + 'message' => 'Package import successful', + 'url' => $p."search/cust_pkg.cgi?pkgbatch=$pkgbatch", + ) +%> + +<% &ntable("#cccccc", 2) %> + + <% include( '/elements/tr-select-agent.html', + #'curr_value' => '', #$agentnum, + 'label' => "<B>Agent</B>", + 'empty_label' => 'Select agent', + ) + %> + + <INPUT TYPE="hidden" NAME="pkgbatch" VALUE="<% $pkgbatch %>"%> + + <TR> + <TH ALIGN="right">Format</TH> + <TD> + <SELECT NAME="format"> + <OPTION VALUE="default" SELECTED>Default + <OPTION VALUE="default-agent_custid">Default with agent_custid + <OPTION VALUE="svc_acct">Account service + <OPTION VALUE="svc_acct-agent_custid">Account service with agent_custid + <OPTION VALUE="svc_phone">Phone service + <OPTION VALUE="svc_phone-agent_custid">Phone service with agent_custid + <OPTION VALUE="svc_external">External service + <OPTION VALUE="svc_external-agent_custid">External service with agent_custid + </SELECT> + </TD> + </TR> + + <% include( '/elements/file-upload.html', + 'field' => 'file', + 'label' => 'Filename', + ) + %> + + <TR> + <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px"> + <INPUT TYPE = "submit" + ID = "submit" + VALUE = "Import file" + onClick = "document.PackageImportForm.submit.disabled=true;" + > + </TD> + </TR> + +</TABLE> + +</FORM> + +<BR> +Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets. The file should have a .CSV or .XLS extension. +<BR><BR> + +<b>Default</b> format has the following field order: <i>custnum<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire</i> +<BR><BR> + +<b>Default with agent_custid</b> format has the following field order: <i>agent_custid<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire</i> +<BR><BR> + +<b>Account service</b> format has the following field order: <i>custnum<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire, username, _password, domsvc</i> +<BR><BR> + +<b>Account service with agent_custid</b> format has the following field order: <i>agent_custid<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire, username, _password, domsvc</i> +<BR><BR> + +<b>Phone sevice</b> format has the following field order: <i>custnum<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire, countrycode, phonenum, sip_password, pin</i> +<BR><BR> + +<b>Phone service with agent_custid</b> format has the following field order: <i>agent_custid<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire, countrycode, phonenum, sip_password, pin</i> +<BR><BR> + +<b>External sevice</b> format has the following field order: <i>custnum<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire, id, title</i> +<BR><BR> + +<b>External service with agent_custid</b> format has the following field order: <i>agent_custid<%$req%>, pkgpart<%$req%>, discountnum, start_date, setup, bill, last_bill, susp, adjourn, cancel, expire, id, title</i> +<BR><BR> + +<%$req%> Required fields +<BR><BR> + +Field information: + +<ul> + + <li><i>custnum</i>: This specifies an existing customer by custnum. + + <li><i>agent_custid</i>: This specifies an existing customer record by agent_custid. + + <li><i>pkgpart</i>: Package definition. Configuration -> Packages -> Package definitions + + <li><i>discountnum</i>: Optional discount. Configuration -> Packages -> Discounts + + <li><i>start_date</i>: Indicates a future start date; do not fill in for active packages + + <li><i>setup</i>: Indicates setup fee has been charged and package setup on this date + + <li><i>bill</i>: Next bill date + + <li><i>last_bill</i>: Last bill date + + <li><i>susp</i>: Indicates the package is suspended (on the given date). + + <li><i>adjourn</i>: Indicates a future suspension on this date. + + <li><i>cancel</i>: Indicates the package is cancelled (on the given date). + + <li><i>expire</i>: Indicates a future cancellation on this date. + +<!-- + <li><i>username</i> and <i>_password</i> are required if <i>pkgpart</i> is specified. (Extended and Extended plus company formats) +--> + + <li><i>domsvc</i>: Domain svcnum + + <li><i>id</i>: External service id, integer + + <li><i>title</i>: External service identifier, text + +</ul> + +<BR> + +<% include('/elements/footer.html') %> + +<%once> + +my $req = qq!<font color="#ff0000">*</font>!; + +</%once> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $pkgbatch = time2str('webimport-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); + +</%init> diff --git a/httemplate/misc/custom_link_proxy.cgi b/httemplate/misc/custom_link_proxy.cgi new file mode 100644 index 0000000..e5934e4 --- /dev/null +++ b/httemplate/misc/custom_link_proxy.cgi @@ -0,0 +1,24 @@ +% if( $response->is_success ) { +<% $response->decoded_content %> +% } +% else { +<% $response->error_as_HTML %> +% } +<%init> + +my( $custnum ) = $cgi->param('custnum'); +my $cust_main = qsearchs('cust_main', { custnum => $custnum } ) + or die "custnum '$custnum' not found"; # just check for existence + +my $conf = new FS::Conf; +my $url = $conf->config('cust_main-custom_link') . $cust_main->custnum; +#warn $url; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right('View customer'); + +my $ua = new LWP::UserAgent; +my $response = $ua->get($url); +</%init> diff --git a/httemplate/misc/delete-domain_record.cgi b/httemplate/misc/delete-domain_record.cgi index 08eedde..200365d 100755 --- a/httemplate/misc/delete-domain_record.cgi +++ b/httemplate/misc/delete-domain_record.cgi @@ -1,7 +1,7 @@ % if ( $error ) { % errorpage($error); % } else { -<% $cgi->redirect($p. "view/svc_domain.cgi?". $domain_record->svcnum) %> +<% $cgi->redirect($p. "view/svc_domain.cgi?". $domain_record->svcnum. '#dns') %> % } <%init> diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index 201aed4..759c8bf 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -1,69 +1,78 @@ <% include('/elements/header.html', $title) %> <FORM NAME="OneTrueForm" ACTION="email-customers.html" METHOD="POST"> -% foreach my $key ( keys %search ) { -% my @values = ref($search{$key}) ? @{$search{$key}} : ( $search{$key} ); -% foreach my $value ( @values ) { - <INPUT TYPE="hidden" NAME="<% $key %>" VALUE="<% $value %>"> -% } -% } +<INPUT TYPE="hidden" NAME="table" VALUE="<% $table %>"> +%# Mixing search params with from address, subject, etc. required special-case +%# handling of those, risked name conflicts, and caused massive problems with +%# multi-valued search params. We are no longer in search context, so we +%# pack the search into a Storable string for later use. +<INPUT TYPE="hidden" NAME="search" VALUE="<% encode_base64(nfreeze(\%search)) %>"> -% if ( $cgi->param('magic') eq 'send' ) { +% if ( $cgi->param('action') eq 'send' ) { <FONT SIZE="+2">Sending notice</FONT> <% include('/elements/progress-init.html', 'OneTrueForm', - [ keys(%search), qw( from subject html_body text_body ) ], + [ qw( search table from subject html_body text_body msgnum ) ], 'process/email-customers.html', { 'message' => "Notice sent" }, #would be nice to show #, but.. ) %> -% } elsif ( $cgi->param('magic') eq 'preview' ) { +% } elsif ( $cgi->param('action') eq 'preview' ) { <FONT SIZE="+2">Preview notice</FONT> % } -% if ( $cgi->param('magic') ) { +% if ( $cgi->param('action') ) { <TABLE BGCOLOR="#cccccc" CELLSPACING=0> + <INPUT TYPE="hidden" NAME="msgnum" VALUE="<% $cgi->param('msgnum') %>"> + +% if ( $msg_template ) { + <% include('/elements/tr-fixed.html', + 'label' => 'Template:', + 'value' => $msg_template->msgname, + ) + %> +% } <% include('/elements/tr-fixed.html', 'field' => 'from', 'label' => 'From:', - 'value' => scalar( $cgi->param('from') ), + 'value' => scalar( $from ), ) %> <% include('/elements/tr-fixed.html', 'field' => 'subject', 'label' => 'Subject:', - 'value' => scalar( $cgi->param('subject') ), + 'value' => scalar( $subject ), ) %> - <INPUT TYPE="hidden" NAME="html_body" VALUE="<% $cgi->param('html_body') |h %>"> + <INPUT TYPE="hidden" NAME="html_body" VALUE="<% $html_body |h %>"> <TR> <TD ALIGN="right" VALIGN="top">Message (HTML display): </TD> - <TD CLASS="background" ALIGN="left"><% $cgi->param('html_body') %></TD> + <TD CLASS="background" ALIGN="left"><% $html_body %></TD> </TR> % my $text_body = HTML::FormatText->new(leftmargin=>0)->format( % HTML::TreeBuilder->new_from_content( -% $cgi->param('html_body') +% $html_body % ) % ); <INPUT TYPE="hidden" NAME="text_body" VALUE="<% $text_body |h %>"> <TR> <TD ALIGN="right" VALIGN="top">Message (Text display): </TD> - <TD CLASS="background" ALIGN="left"><PRE><% $text_body %></PRE></TD> + <TD CLASS="background" STYLE="background-color:white" ALIGN="left"><PRE><% $text_body %></PRE></TD> </TR> </TABLE> -% if ( $cgi->param('magic') eq 'preview' ) { +% if ( $cgi->param('action') eq 'preview' ) { <SCRIPT> function areyousure(href) { @@ -72,15 +81,29 @@ </SCRIPT> <BR> - <INPUT TYPE="hidden" NAME="magic" VALUE="send"> + <INPUT TYPE="hidden" NAME="action" VALUE="send"> <INPUT TYPE="submit" VALUE="Send notice" onClick="return areyousure()"> % } % } else { - <TABLE BGCOLOR="#cccccc" CELLSPACING=0 WIDTH="100%"> +<SCRIPT TYPE="text/javascript"> +function toggle(obj) { + document.getElementById('table_no_template').style.display = (obj.value == 0) ? '' : 'none'; +} +</SCRIPT> +Template: + <% include('/elements/select-table.html', + 'label' => 'Template:', + 'table' => 'msg_template', + 'name_col' => 'msgname', + 'empty_label' => '(none)', + 'onchange' => 'toggle(this)', + ) + %><BR> + <TABLE BGCOLOR="#cccccc" CELLSPACING=0 WIDTH="100%" id="table_no_template"> <% include('/elements/tr-input-text.html', 'field' => 'from', 'label' => 'From:', @@ -102,15 +125,14 @@ %#Substitution vars: - <BR><BR> - <INPUT TYPE="hidden" NAME="magic" VALUE="preview"> + <INPUT TYPE="hidden" NAME="action" VALUE="preview"> <INPUT TYPE="submit" VALUE="Preview notice"> % } </FORM> -% if ( $cgi->param('magic') eq 'send' ) { +% if ( $cgi->param('action') eq 'send' ) { <SCRIPT TYPE="text/javascript"> process(); </SCRIPT> @@ -123,16 +145,32 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Bulk send customer notices'); -my %search = $cgi->Vars; -delete $search{$_} for qw( magic from subject html_body text_body ); -$search{$_} = [ split(/\0/, $search{$_}) ] - foreach grep { $_ eq 'payby' || $search{$_} =~ /\0/ } keys %search; - -my $title = 'Bulk send customer notices'; +my $table = $cgi->param('table') or die "'table' required"; +my %search; +if ( $cgi->param('search') ) { + %search = %{ thaw(decode_base64($cgi->param('search'))) }; +} +else { + %search = $cgi->Vars; + delete $search{$_} for qw( action table from subject html_body text_body ); + # FS::$table->search is expected to know which parameters might be + # multi-valued, and to accept scalar values for them also. No good + # solution to this since CGI can't tell whether a parameter _might_ + # have had multiple values, only whether it does. + @search{keys %search} = map { /\0/ ? [ split /\0/, $_ ] : $_ } values %search; +} + +my $title = 'Send bulk customer notices'; my $num_cust; -if ( $cgi->param('magic') eq 'preview' ) { - my $sql_query = FS::cust_main->search(\%search); +my $from = $cgi->param('from') || ''; +my $subject = $cgi->param('subject') || ''; +my $html_body = $cgi->param('html_body') || ''; + +my $msg_template = ''; + +if ( $cgi->param('action') eq 'preview' ) { + my $sql_query = "FS::$table"->search(\%search); my $count_query = delete($sql_query->{'count_query'}); my $count_sth = dbh->prepare($count_query) or die "Error preparing $count_query: ". dbh->errstr; @@ -140,6 +178,17 @@ if ( $cgi->param('magic') eq 'preview' ) { or die "Error executing $count_query: ". $count_sth->errstr; my $count_arrayref = $count_sth->fetchrow_arrayref; $num_cust = $count_arrayref->[0]; + + if ( $cgi->param('msgnum') ) { + $msg_template = qsearchs('msg_template', + { msgnum => $cgi->param('msgnum') } ) + or die "template not found: ".$cgi->param('msgnum'); + $sql_query->{'extra_sql'} .= ' LIMIT 1'; + $sql_query->{'order_by'} = ''; + my $cust = qsearchs($sql_query)->cust_main; + my %message = $msg_template->prepare( 'cust_main' => $cust ); + ($from, $subject, $html_body) = @message{'from', 'subject', 'html_body'}; + } } </%init> diff --git a/httemplate/misc/merge_cust.html b/httemplate/misc/merge_cust.html new file mode 100644 index 0000000..ad075be --- /dev/null +++ b/httemplate/misc/merge_cust.html @@ -0,0 +1,72 @@ +<% include('/elements/header-popup.html', 'Merge customer' ) %> + +<% include('/elements/error.html') %> + +<FORM NAME="cust_merge_popup" ID="cust_merge_popup" ACTION="<% popurl(1) %>cust_main-merge.html" METHOD=POST onSubmit="submit_merge(); return false;"> + +<SCRIPT TYPE="text/javascript"> + +var submit_interval_id; +function submit_merge() { + document.getElementById('confirm_merge_cust_button').disabled = 'true'; + smart_new_custnum_search(document.getElementById('new_custnum_search')); + submit_interval_id = setInterval( do_submit_merge, 100); +} + +function do_submit_merge() { + + if ( new_custnum_search_active ) + return; + + document.getElementById('confirm_merge_cust_button').disabled = ''; + + clearInterval(submit_interval_id); + + if ( document.cust_merge_popup.new_custnum.value != '' ) { + document.cust_merge_popup.submit(); + } + +} + +</SCRIPT> + +</SCRIPT> + +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> + +<TABLE BORDER="0" CELLSPACING="2" STYLE="margin-left:auto; margin-right:auto"> + <% include('/elements/tr-search-cust_main.html', + 'label' => 'Merge into: ', + 'field' => 'new_custnum', + 'find_button' => 1, + 'curr_value' => scalar($cgi->param('new_custnum')), + ) + %> +</TABLE> + +<P ALIGN="CENTER"> +%#have merge button start out disabled and enable after you select a target cust +<INPUT TYPE="submit" NAME="confirm_merge_cust_button" ID="confirm_merge_cust_button" VALUE="Merge customer"> <INPUT TYPE="BUTTON" VALUE="Don't merge" onClick="parent.cClick();"> + +</FORM> +</BODY> +</HTML> + +<%init> + +$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; +my $custnum = $1; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" unless $curuser->access_right('Merge customer'); + +my $cust_main = qsearchs( { + 'table' => 'cust_main', + 'hashref' => { 'custnum' => $custnum }, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +} ); +die "No customer # $custnum" unless $cust_main; + +</%init> + diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 33b2bb3..b232deb 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -9,14 +9,14 @@ function enable_order_pkg () { if ( document.OrderPkgForm.pkgpart.selectedIndex > 0 ) { - document.OrderPkgForm.submit.disabled = false; + document.OrderPkgForm.submitButton.disabled = false; if ( document.OrderPkgForm.pkgpart.options[document.OrderPkgForm.pkgpart.selectedIndex].getAttribute('data-can_discount') == 1 ) { document.OrderPkgForm.discountnum.disabled = false; } else { document.OrderPkgForm.discountnum.disabled = true; } } else { - document.OrderPkgForm.submit.disabled = true; + document.OrderPkgForm.submitButton.disabled = true; document.OrderPkgForm.discountnum.disabled = true; } } @@ -38,34 +38,19 @@ ) %> -%# false laziness w/edit/quick-charge.html <TR> <TH ALIGN="right">Start date </TD> <TD COLSPAN=6> - <INPUT TYPE = "text" - NAME = "start_date" - SIZE = 32 - ID = "start_date_text" - VALUE = "<% $start_date %>" - > - <IMG SRC = "../images/calendar.png" - ID = "start_date_button" - STYLE = "cursor: pointer" - TITLE = "Select date" - > + <% include('/elements/input-date-field.html',{ + 'name' => 'start_date', + 'format' => $date_format, + 'value' => $start_date, + 'noinit' => 1, + }) %> <FONT SIZE=-1>(leave blank to start immediately)</FONT> </TD> </TR> -<SCRIPT TYPE="text/javascript"> - Calendar.setup({ - inputField: "start_date_text", - ifFormat: "<% $date_format %>", - button: "start_date_button", - align: "BR" - }); -</SCRIPT> - % if ( $cust_main->payby =~ /^(CARD|CHEK)$/ ) { % my $what = lc(FS::payby->shortname($cust_main->payby)); <TR> @@ -99,10 +84,30 @@ ) %> +<TR> + <TH ALIGN="right">Contract end date </TD> + <TD COLSPAN=6> + <% include('/elements/input-date-field.html',{ + 'name' => 'contract_end', + 'format' => $date_format, + 'value' => '', + 'noinit' => 1, + }) %> + </TD> +</TR> + </TABLE> +<% include( '/elements/standardize_locations.html', + 'form' => "OrderPkgForm", + 'onlyship' => 1, + 'no_company' => 1, + 'callback' => 'document.OrderPkgForm.submit();', + ) +%> + <BR> -<INPUT NAME="submit" TYPE="submit" VALUE="Order Package" <% $pkgpart ? '' : 'DISABLED' %>> +<INPUT NAME="submitButton" TYPE="button" VALUE="Order Package" onClick = "this.disabled=true; standardize_locations();" <% $pkgpart ? '' : 'DISABLED' %>> </FORM> </BODY> @@ -128,7 +133,10 @@ my $cust_main = qsearchs({ my $pkgpart = scalar($cgi->param('pkgpart')); my $format = $date_format. ' %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 $start_date = ''; +if( ! $conf->exists('order_pkg-no_start_date') ) { + $start_date = $cust_main->next_bill_date; + $start_date = $start_date ? time2str($format, $start_date) : ''; +} </%init> diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi index 813b560..bcab68a 100644 --- a/httemplate/misc/payment.cgi +++ b/httemplate/misc/payment.cgi @@ -67,6 +67,11 @@ % } +<% include('/elements/tr-select-discount_term.html', + 'custnum' => $custnum, + 'cgi' => $cgi + ) +%> % if ( $payby eq 'CARD' ) { % diff --git a/httemplate/misc/process/batch-cust_pay.cgi b/httemplate/misc/process/batch-cust_pay.cgi index 058a225..e51b9e6 100644 --- a/httemplate/misc/process/batch-cust_pay.cgi +++ b/httemplate/misc/process/batch-cust_pay.cgi @@ -10,13 +10,33 @@ % #my $row = 0; % #while ( exists($param->{"custnum$row"}) ) { % for ( my $row = 0; exists($param->{"custnum$row"}); $row++ ) { +% my $custnum = $param->{"custnum$row"}; +% my $cust_main; +% if ( $custnum =~ /^(\d+)$/ and $1 <= 2147483647 ) { +% $cust_main = qsearchs({ +% 'table' => 'cust_main', +% 'hashref' => { 'custnum' => $1 }, +% 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +% }); +% } +% if ( !$cust_main ) { # not found, try agent_custid +% $cust_main = qsearchs({ +% 'table' => 'cust_main', +% 'hashref' => { 'agent_custid' => $custnum }, +% 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +% }); +% } +% $custnum = $cust_main->custnum if $cust_main; +% # if !$cust_main, then this will throw an error on batch_insert +% % push @cust_pay, new FS::cust_pay { -% 'custnum' => $param->{"custnum$row"}, -% 'paid' => $param->{"paid$row"}, -% 'payby' => 'BILL', -% 'payinfo' => $param->{"payinfo$row"}, -% 'paybatch' => $paybatch, -% } +% 'custnum' => $custnum, +% 'paid' => $param->{"paid$row"}, +% 'payby' => 'BILL', +% 'payinfo' => $param->{"payinfo$row"}, +% 'discount_term' => $param->{"discount_term$row"}, +% 'paybatch' => $paybatch, +% } % if $param->{"custnum$row"} % || $param->{"paid$row"} % || $param->{"payinfo$row"}; @@ -42,6 +62,6 @@ % } else { % % -<% $cgi->redirect(popurl(3). "search/cust_pay.cgi?magic=paybatch;paybatch=$paybatch") %> +<% $cgi->redirect(popurl(3). "search/cust_pay.html?magic=paybatch;paybatch=$paybatch") %> % } diff --git a/httemplate/misc/process/cust_main-import_charges.cgi b/httemplate/misc/process/cust_main-import_charges.cgi index 3ca6894..bda3e3b 100644 --- a/httemplate/misc/process/cust_main-import_charges.cgi +++ b/httemplate/misc/process/cust_main-import_charges.cgi @@ -16,7 +16,8 @@ my $fh = $cgi->upload('csvfile'); my $error = defined($fh) ? FS::cust_main::batch_charge( { filehandle => $fh, - 'fields' => [qw( custnum amount pkg )], + 'agentnum' => scalar($cgi->param('agentnum')), + 'format' => scalar($cgi->param('format')), } ) : 'No file'; diff --git a/httemplate/misc/process/cust_main_note-import.cgi b/httemplate/misc/process/cust_main_note-import.cgi index 6aa8b1d..6625e00 100644 --- a/httemplate/misc/process/cust_main_note-import.cgi +++ b/httemplate/misc/process/cust_main_note-import.cgi @@ -26,6 +26,7 @@ The following items <% $op eq 'Preview' ? 'would be' : 'were' %> imported. (See die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Import'); +$FS::cust_main::import=1; # the customer records are already in the database my $date = time; my $otaker = $FS::CurrentUser::CurrentUser->username; my $csv = new Text::CSV_XS; @@ -38,25 +39,27 @@ my @inserted = (); my @uninserted = (); for ( my $row = 0; exists($param->{"custnum$row"}); $row++ ) { if ( $param->{"custnum$row"} ) { -# my $cust_main_note = new FS::cust_main_note { -# 'custnum' => $param->{"custnum$row"}, -# '_date' => $date, -# 'otaker' => $otaker, -# 'comments' => $param->{"note$row"}, -# }; -# my $error = ''; -# $error = $cust_main_note->insert unless ($op eq "Preview"); - my $cust_main = qsearchs('cust_main', - { 'custnum' => $param->{"custnum$row"} } - ); - my $error; - if ($cust_main) { - $cust_main->comments - ? $cust_main->comments($cust_main->comments. " ". $param->{"note$row"}) - : $cust_main->comments($param->{"note$row"}); - $error = $cust_main->replace; - }else{ - $error = "Can't find customer " . $param->{"custnum$row"}; + my $error = ''; + if ( $param->{use_comments} ) { # why? notes are sexier + my $cust_main = qsearchs('cust_main', + { 'custnum' => $param->{"custnum$row"} } + ); + if ($cust_main) { + $cust_main->comments + ? $cust_main->comments($cust_main->comments. " ". $param->{"note$row"}) + : $cust_main->comments($param->{"note$row"}); + $error = $cust_main->replace; + }else{ + $error = "Can't find customer " . $param->{"custnum$row"}; + } + } else { + my $cust_main_note = new FS::cust_main_note { + 'custnum' => $param->{"custnum$row"}, + '_date' => $date, + 'otaker' => $otaker, + 'comments' => $param->{"note$row"}, + }; + $error = $cust_main_note->insert unless ($op eq "Preview"); } my $result = { 'custnum' => $param->{"custnum$row"}, 'last' => $param->{"last$row"}, diff --git a/httemplate/misc/process/cust_pay-import.cgi b/httemplate/misc/process/cust_pay-import.cgi index d4ff226..92b6e5a 100644 --- a/httemplate/misc/process/cust_pay-import.cgi +++ b/httemplate/misc/process/cust_pay-import.cgi @@ -1,4 +1,4 @@ -<% $cgi->redirect(popurl(3). "search/cust_pay.cgi?magic=paybatch;paybatch=$paybatch") %> +<% $cgi->redirect(popurl(3). "search/cust_pay.html?magic=paybatch;paybatch=$paybatch") %> <%init> my $fh = $cgi->upload('csvfile'); diff --git a/httemplate/misc/process/cust_pkg-import.html b/httemplate/misc/process/cust_pkg-import.html new file mode 100644 index 0000000..1021817 --- /dev/null +++ b/httemplate/misc/process/cust_pkg-import.html @@ -0,0 +1,10 @@ +<% $server->process %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Import'); + +my $server = + new FS::UI::Web::JSRPC 'FS::cust_pkg::Import::process_batch_import', $cgi; + +</%init> diff --git a/httemplate/misc/process/delete-customer.cgi b/httemplate/misc/process/delete-customer.cgi index d509a5e..1201131 100755 --- a/httemplate/misc/process/delete-customer.cgi +++ b/httemplate/misc/process/delete-customer.cgi @@ -28,6 +28,6 @@ if ( $cgi->param('new_custnum') ) { my $cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } ) or die "Customer not found: $custnum"; -my $error = $cust_main->delete($new_custnum); +my $error = $cust_main->delete('new_custnum' => $new_custnum); </%init> diff --git a/httemplate/misc/process/email-customers.html b/httemplate/misc/process/email-customers.html index c54bc6d..de2bb92 100644 --- a/httemplate/misc/process/email-customers.html +++ b/httemplate/misc/process/email-customers.html @@ -4,6 +4,6 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Bulk send customer notices'); -my $server = new FS::UI::Web::JSRPC 'FS::cust_main::process_email_search_result', $cgi; +my $server = new FS::UI::Web::JSRPC 'FS::cust_main_Mixin::process_email_search_result', $cgi; </%init> diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi index 665001e..c1c9071 100644 --- a/httemplate/misc/process/payment.cgi +++ b/httemplate/misc/process/payment.cgi @@ -119,19 +119,26 @@ if ( $payby eq 'CHEK' ) { die "unknown payby $payby"; } +$cgi->param('discount_term') =~ /^\d*$/ + or errorpage("illegal discount_term"); +my $discount_term = $1; + my $error = ''; my $paynum = ''; if ( $cgi->param('batch') ) { - $error = $cust_main->batch_card( - 'payby' => $payby, - 'amount' => $amount, - 'payinfo' => $payinfo, - 'paydate' => "$year-$month-01", - 'payname' => $payname, - map { $_ => $cgi->param($_) } - @{$payby2fields{$payby}} - ); + $error = 'Prepayment discounts not supported with batched payments' + if $discount_term; + + $error ||= $cust_main->batch_card( + 'payby' => $payby, + 'amount' => $amount, + 'payinfo' => $payinfo, + 'paydate' => "$year-$month-01", + 'payname' => $payname, + map { $_ => $cgi->param($_) } + @{$payby2fields{$payby}} + ); errorpage($error) if $error; } else { @@ -146,6 +153,7 @@ if ( $cgi->param('batch') ) { 'payunique' => $payunique, 'paycvv' => $paycvv, 'paynum_ref' => \$paynum, + 'discount_term' => $discount_term, map { $_ => $cgi->param($_) } @{$payby2fields{$payby}} ); errorpage($error) if $error; diff --git a/httemplate/misc/timeworked.html b/httemplate/misc/timeworked.html index 46063e8..672fad8 100755 --- a/httemplate/misc/timeworked.html +++ b/httemplate/misc/timeworked.html @@ -8,22 +8,11 @@ <THEAD> <TR> - <TH>Trans</TH> <TH COLSPAN="2">Ticket</TH> - <TH>Time</TH> + <TH>Hours</TH> <TH COLSPAN="2">Customer</TH> <TH>Multiplier</TH> </TR> - - <TR> - <TH>#</TH> - <TH>#</TH> - <TH>Subject</TH> - <TH>hours</TH> - <TH>#</TH> - <TH>Name</TH> - <TH></TH> - </TR> </THEAD> <TBODY> @@ -35,9 +24,9 @@ % my ($custnum, $name) = split(':', pop @customers, 2); % my $link = $p. 'rt/Ticket/Display.html?id='. $ticketmap{$tr_id}. % '#txn-'. $tr_id; +% my $clink = $p. 'view/cust_main.cgi?'. $custnum; <TR> - <TD><a href="<% $link %>"><% $tr_id %></a></TD> <TD><a href="<% $link %>"><% $ticketmap{$tr_id} %></a></TD> <TD><a href="<% $link %>"><% $ticket{$ticketmap{$tr_id}} |h %></a></TD> @@ -47,8 +36,8 @@ % } <TD><% sprintf("%0.2f", $seconds/3600) %></TD> - <TD ALIGN="right"><% $custnum %></TD> - <TD ALIGN="right"><% $name %></TD> + <TD ALIGN="right"><a href="<% $clink %>"><% $custnum %></a></TD> + <TD ALIGN="right"><a href="<% $clink %>"><% $name %></a></TD> <TD> <INPUT TYPE="hidden" NAME="transactionid<%$tr_id%>" VALUE="1" > <INPUT TYPE="hidden" NAME="seconds<%$tr_id%>" VALUE="<% $seconds %>" > @@ -65,10 +54,11 @@ % foreach ( @customers ) { % ($custnum, $name) = split(':', $_, 2); +% $clink = $p. 'view/cust_main.cgi?'. $custnum; <TR> - <TD ALIGN="right" COLSPAN="5" ><% $custnum %></TD> - <TD ALIGN="right"><% $name %></TD> + <TD ALIGN="right" COLSPAN="4" ><a href="<% $clink %>"><% $custnum %></a></TD> + <TD ALIGN="right"><a href="<% $clink %>"><% $name %></a></TD> <TD> % $multiplier = $default_multiplier; diff --git a/httemplate/misc/unprovision.cgi b/httemplate/misc/unprovision.cgi index 4ab15fd..6f2c238 100755 --- a/httemplate/misc/unprovision.cgi +++ b/httemplate/misc/unprovision.cgi @@ -1,6 +1,8 @@ %if ( $error ) { % errorpage($error); -%} else { +%} elsif ( $pkgnum ) { +<% $cgi->redirect(popurl(2)."search/cust_pkg_svc.html?svcpart=$svcpart;pkgnum=$pkgnum") %> +%} else { # $custnum should always exist <% $cgi->redirect(popurl(2)."view/cust_main.cgi?$custnum") %> %} <%init> @@ -9,18 +11,28 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Unprovision customer service'); #untaint svcnum -my($query) = $cgi->keywords; -$query =~ /^(\d+)$/; -my $svcnum = $1; +my @svcnums; +my ($pkgnum, $svcpart, $custnum); +if( $cgi->param('svcnum') ) { + @svcnums = grep { $_ } map { /^(\d+)$/ && $1 } $cgi->param('svcnum'); + $pkgnum = $cgi->param('pkgnum'); + $svcpart = $cgi->param('svcpart'); + $custnum = $cgi->param('custnum'); +} +else { + @svcnums = map { /^(\d+)$/ && $1 } $cgi->keywords; +} -#my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum}); -#die "Unknown svcnum!" unless $svc_acct; +my $error = ''; +foreach my $svcnum (@svcnums) { -my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum}); -die "Unknown svcnum!" unless $cust_svc; + my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum}); + die "Unknown svcnum!" unless $cust_svc; -my $custnum = $cust_svc->cust_pkg->custnum; + $custnum ||= $cust_svc->cust_pkg->custnum; -my $error = $cust_svc->cancel; + $error .= $cust_svc->cancel; + +} </%init> diff --git a/httemplate/misc/xmlhttp-cust_main-address_standardize.html b/httemplate/misc/xmlhttp-cust_main-address_standardize.html index 3b9e142..d0627cd 100644 --- a/httemplate/misc/xmlhttp-cust_main-address_standardize.html +++ b/httemplate/misc/xmlhttp-cust_main-address_standardize.html @@ -28,6 +28,7 @@ if ( $sub eq 'address_standardize' ) { } ); foreach my $pre ( '', 'ship_' ) { + next unless ($pre || !$arg{onlyship}); my($zip5, $zip4) = split('-',$arg{$pre.'zip'}); diff --git a/httemplate/misc/xmlhttp-cust_main-censustract.html b/httemplate/misc/xmlhttp-cust_main-censustract.html index 9d588d7..3ba68af 100644 --- a/httemplate/misc/xmlhttp-cust_main-censustract.html +++ b/httemplate/misc/xmlhttp-cust_main-censustract.html @@ -36,23 +36,32 @@ if ( $sub eq 'censustract' ) { my $content = $res->content; my $p = new HTML::TokeParser \$content; my $viewstate; + my $eventvalidation; while (my $token = $p->get_tag('input') ) { - next unless $token->[1]->{name} eq '__VIEWSTATE'; - $viewstate = $token->[1]->{value}; - last; + if ($token->[1]->{name} eq '__VIEWSTATE') { + $viewstate = $token->[1]->{value}; + } + if ($token->[1]->{name} eq '__EVENTVALIDATION') { + $eventvalidation = $token->[1]->{value}; + } + last if $viewstate && $eventvalidation; } - unless ($viewstate) { + unless ($viewstate && $eventvalidation ) { - $error = "no __VIEWSTATE found"; + $error = "either no __VIEWSTATE or __EVENTVALIDATION found"; } else { my($zip5, $zip4) = split('-',$arg{zip}); + #ugh workaround a mess at ffiec + $arg{year} = " $arg{year}" unless $arg{year} = "2010"; my @ffiec_args = ( __VIEWSTATE => $viewstate, + __EVENTVALIDATION => $eventvalidation, ddlbYear => $arg{year}, + ddlbYear => ' 2009', txtAddress => $arg{address}, txtCity => $arg{city}, ddlbState => $arg{state}, @@ -62,6 +71,7 @@ if ( $sub eq 'censustract' ) { warn join("\n", @ffiec_args ) if $DEBUG; + push @{ $ua->requests_redirectable }, 'POST'; $res = $ua->request( POST( $url, \@ffiec_args ) ); warn $res->as_string if $DEBUG > 1; @@ -74,6 +84,7 @@ if ( $sub eq 'censustract' ) { my @id = qw( MSACode StateCode CountyCode TractCode ); $content = $res->content; + warn $res->content if $DEBUG > 1; $p = new HTML::TokeParser \$content; my $prefix = 'UcGeoResult11_lb'; my $compare = diff --git a/httemplate/misc/xmlhttp-cust_main-discount_terms.cgi b/httemplate/misc/xmlhttp-cust_main-discount_terms.cgi new file mode 100644 index 0000000..71e2da5 --- /dev/null +++ b/httemplate/misc/xmlhttp-cust_main-discount_terms.cgi @@ -0,0 +1,24 @@ +% if ( $sub eq 'discount_terms' ) { +% +% my $return = []; +% my $custnum = $cgi->param('arg'); +% my $cust_main = ''; +% $cust_main = qsearchs({ +% 'table' => 'cust_main', +% 'hashref' => { 'custnum' => $custnum }, +% 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +% }); +% +% if ($cust_main) { +% $return = [ map [ $_, "$_ months" ], $cust_main->discount_terms ]; +% } +% +<% objToJson($return) %> +% } +<%init> + +my $conf = new FS::Conf; + +my $sub = $cgi->param('sub'); + +</%init> diff --git a/httemplate/misc/xmlhttp-cust_main-search.cgi b/httemplate/misc/xmlhttp-cust_main-search.cgi index 26e68b5..481bea2 100644 --- a/httemplate/misc/xmlhttp-cust_main-search.cgi +++ b/httemplate/misc/xmlhttp-cust_main-search.cgi @@ -2,10 +2,10 @@ % % my $custnum = $cgi->param('arg'); % my $cust_main = ''; -% if ( $custnum <= 2147483647 ) { +% if ( $custnum =~ /^(\d+)$/ and $1 <= 2147483647 ) { % $cust_main = qsearchs({ % 'table' => 'cust_main', -% 'hashref' => { 'custnum' => $custnum }, +% 'hashref' => { 'custnum' => $1 }, % 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, % }); % } @@ -22,7 +22,9 @@ % } elsif ( $sub eq 'smart_search' ) { % % my $string = $cgi->param('arg'); -% my @cust_main = smart_search( 'search' => $string ); +% my @cust_main = smart_search( 'search' => $string, +% 'no_fuzzy_on_exact' => 1, #pref? +% ); % my $return = [ map [ $_->custnum, $_->name ], @cust_main ]; % <% objToJson($return) %> |