diff options
Diffstat (limited to 'httemplate/misc')
-rw-r--r-- | httemplate/misc/batch-cust_pay.html | 375 | ||||
-rwxr-xr-x | httemplate/misc/cancel_pkg.html | 79 | ||||
-rw-r--r-- | httemplate/misc/cust-part_pkg.cgi | 18 | ||||
-rwxr-xr-x | httemplate/misc/cust_main-cancel.cgi | 2 | ||||
-rw-r--r-- | httemplate/misc/cust_main-import.cgi | 4 | ||||
-rwxr-xr-x | httemplate/misc/cust_main-suspend.cgi | 75 | ||||
-rwxr-xr-x | httemplate/misc/cust_main-unsuspend.cgi | 56 | ||||
-rw-r--r-- | httemplate/misc/delete-ftp_target.html | 18 | ||||
-rw-r--r-- | httemplate/misc/download-batch.cgi | 13 | ||||
-rw-r--r-- | httemplate/misc/order_pkg.html | 14 | ||||
-rw-r--r-- | httemplate/misc/process/batch-cust_pay.cgi | 115 | ||||
-rwxr-xr-x | httemplate/misc/process/cancel_pkg.html | 40 | ||||
-rw-r--r-- | httemplate/misc/suspend_cust.html | 79 | ||||
-rw-r--r-- | httemplate/misc/unsuspend_cust.html | 68 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-cust_bill-search.html | 18 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-cust_main-discount_terms.cgi | 19 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-cust_main-search.cgi | 90 |
17 files changed, 935 insertions, 148 deletions
diff --git a/httemplate/misc/batch-cust_pay.html b/httemplate/misc/batch-cust_pay.html index 11fdeee61..887b92489 100644 --- a/httemplate/misc/batch-cust_pay.html +++ b/httemplate/misc/batch-cust_pay.html @@ -1,6 +1,9 @@ -<% include('/elements/header.html', 'Quick payment entry') %> +<& /elements/header.html, { + title => 'Quick payment entry', + etc => 'onload="preload()"' +} &> -<% include('/elements/error.html') %> +<& /elements/error.html &> <SCRIPT TYPE="text/javascript"> function warnUnload() { @@ -14,6 +17,21 @@ function warnUnload() { } window.onbeforeunload = warnUnload; +function add_row_callback(rownum, prefix) { + document.getElementById('enable_app'+rownum).disabled = true; +} + +function custnum_update_callback(rownum, prefix) { + var custnum = document.getElementById('custnum'+rownum).value; + document.getElementById('enable_app'+rownum).disabled = ( + custnum == 0 || + num_open_invoices[rownum] < 2 + ); +% if ( $use_discounts ) { + select_discount_term(rownum, prefix); +% } +} + function select_discount_term(row, prefix) { var custnum_obj = document.getElementById('custnum'+prefix+row); var select_obj = document.getElementById('discount_term'+prefix+row); @@ -46,6 +64,265 @@ function select_discount_term(row, prefix) { discount_terms(custnum_obj.value, select_discount_term_update); } + +var invoices_for_row = new Object; + +function update_invoices(rownum, invoices) { + invoices_for_row[rownum] = new Object; + // only called before create_application_row + for ( var i=0; i<invoices.length; i++ ) { + invoices_for_row[rownum][ invoices[i].invnum ] = invoices[i]; + } +} + +function toggle_application_row(ev, next) { + if (!next) next = function(){}; //optional continuation + var rownum = this.getAttribute('rownum'); + if ( this.checked ) { + var custnum = document.getElementById('custnum'+rownum).value; + if (!custnum) return; + lock_payment_row(rownum, true); + custnum_search_open( custnum, + function(returned) { + update_invoices(rownum, JSON.parse(returned)); + create_application_row(rownum, 0); + next.call(this, rownum); + } + ); + } +} + +function lock_payment_row(rownum, flag) { +% foreach (qw(invnum custnum customer)) { + obj = document.getElementById('<% $_ %>'+rownum); + obj.readOnly = flag; +% } + document.getElementById('enable_app'+rownum).disabled = flag; +} + +function delete_application_row() { + var rownum = this.getAttribute('rownum'); + var appnum = this.getAttribute('appnum'); + var tr_app = document.getElementById('row'+rownum+'.'+appnum); + var select_invnum = document.getElementById('invnum'+rownum+'.'+appnum); + if ( select_invnum.value ) { + invoices_for_row[rownum][ select_invnum.value ] = select_invnum.curr_invoice; + } + + tr_app.parentNode.removeChild(tr_app); + if ( appnum > 0 ) { + document.getElementById('delete'+rownum+'.'+(appnum-1)).style.display = ''; + } + else { + lock_payment_row(rownum, false); + document.getElementById('enable_app'+rownum).checked = false; + } +} + +function amount_unapplied(rownum) { + var appnum = 0; + var total = 0; + var payment_amount = parseFloat(document.getElementById('paid'+rownum).value) + || 0; + while (true) { + var input_amount = document.getElementById('amount'+rownum+'.'+appnum); + if ( input_amount ) { + total += parseFloat(input_amount.value || 0); + appnum++; + } + else { + return payment_amount - total; + } + } +} + +var change_app_amount; + +function choose_app_invnum() { + var rownum = this.getAttribute('rownum'); + var appnum = this.getAttribute('appnum'); + var last_invoice = this.curr_invoice; + if ( last_invoice ) { + invoices_for_row[rownum][ last_invoice['invnum'] ] = last_invoice; + } + + if ( this.value ) { + var this_invoice = invoices_for_row[rownum][this.value]; + this.curr_invoice = invoices_for_row[rownum][this.value]; + var span_owed = document.getElementById('owed'+rownum+'.'+appnum); + span_owed.innerHTML = this_invoice['owed'] + ' '; + delete invoices_for_row[rownum][this.value]; + + var input_amount = document.getElementById('amount'+rownum+'.'+appnum); + if ( input_amount.value == '' ) { + input_amount.value = + Math.max( + 0, Math.min( amount_unapplied(rownum), this_invoice['owed']) + ).toFixed(2); + // trigger onchange + change_app_amount.call(input_amount); + } + } +} + +function focus_app_invnum() { +% # invoice numbers just display as invoice numbers + var rownum = this.getAttribute('rownum'); + var add_opt = function(obj, value) { + var o = document.createElement('OPTION'); + o.text = value; + o.value = value; + obj.add(o); + } + this.options.length = 0; + var this_invoice = this.curr_invoice; + if ( this_invoice ) { + add_opt(this, this_invoice.invnum); + } else { + add_opt(this, ''); + } + for ( var x in invoices_for_row[rownum] ) { + add_opt(this, invoices_for_row[rownum][x].invnum); + } +} + +function change_app_amount() { + var rownum = this.getAttribute('rownum'); + var appnum = this.getAttribute('appnum'); +%# maybe some kind of warning if amount_unapplied < 0? +%# only spawn a new application row if there are open invoices left, +%# and this is the highest-numbered application row for the customer, +%# and the sum of the applied amounts is < the amount of the payment, + if ( Object.keys(invoices_for_row[rownum]).length > 0 + && !document.getElementById( 'row'+rownum+'.'+(parseInt(appnum) + 1) ) + && amount_unapplied(rownum) > 0 ) { + + create_application_row(rownum, parseInt(appnum) + 1); + + } +} + +function create_application_row(rownum, appnum) { + var payment_row = document.getElementById('row'+rownum); + var tr_app = document.createElement('TR'); + tr_app.setAttribute('rownum', rownum); + tr_app.setAttribute('appnum', appnum); + tr_app.setAttribute('id', 'row'+rownum+'.'+appnum); + + var td_invnum = document.createElement('TD'); + td_invnum.setAttribute('colspan', 4); + td_invnum.style.textAlign = 'right'; + td_invnum.appendChild( + document.createTextNode('<% mt('Apply to Invoice ') %>') + ); + var select_invnum = document.createElement('SELECT'); + select_invnum.setAttribute('rownum', rownum); + select_invnum.setAttribute('appnum', appnum); + select_invnum.setAttribute('id', 'invnum'+rownum+'.'+appnum); + select_invnum.setAttribute('name', 'invnum'+rownum+'.'+appnum); + select_invnum.style.textAlign = 'right'; + select_invnum.style.width = '50px'; + select_invnum.onchange = choose_app_invnum; + select_invnum.onfocus = focus_app_invnum; + + td_invnum.appendChild(select_invnum); + tr_app.appendChild(td_invnum); + + var td_owed = document.createElement('TD'); + td_owed.style.textAlign= 'right'; + var span_owed = document.createElement('SPAN'); + span_owed.setAttribute('rownum', rownum); + span_owed.setAttribute('appnum', appnum); + span_owed.setAttribute('id', 'owed'+rownum+'.'+appnum); + td_owed.appendChild(span_owed); + tr_app.appendChild(td_owed); + + var td_amount = document.createElement('TD'); + td_amount.style.textAlign = 'right'; + var input_amount = document.createElement('INPUT'); + input_amount.size = 6; + input_amount.setAttribute('rownum', rownum); + input_amount.setAttribute('appnum', appnum); + input_amount.setAttribute('name', 'amount'+rownum+'.'+appnum); + input_amount.setAttribute('id', 'amount'+rownum+'.'+appnum); + input_amount.style.textAlign = 'right'; + input_amount.onchange = change_app_amount; + td_amount.appendChild(input_amount); + tr_app.appendChild(td_amount); + + var td_delete = document.createElement('TD'); + td_delete.setAttribute('colspan', <% scalar(@fields)-2 %>); + var button_delete = document.createElement('INPUT'); + button_delete.setAttribute('rownum', rownum); + button_delete.setAttribute('appnum', appnum); + button_delete.setAttribute('id', 'delete'+rownum+'.'+appnum); + button_delete.setAttribute('type', 'button'); + button_delete.setAttribute('value', 'X'); + button_delete.onclick = delete_application_row; + button_delete.style.color = '#ff0000'; + button_delete.style.fontWeight = 'bold'; + button_delete.style.paddingLeft = '2px'; + button_delete.style.paddingRight = '2px'; + td_delete.appendChild(button_delete); + tr_app.appendChild(td_delete); + + var td_error = document.createElement('TD'); + var span_error = document.createElement('SPAN'); + span_error.setAttribute('rownum', rownum); + span_error.setAttribute('appnum', appnum); + span_error.setAttribute('id', 'error'+rownum+'.'+appnum); + span_error.style.color = '#ff0000'; + td_error.appendChild(span_error); + tr_app.appendChild(td_error); + + if ( appnum > 0 ) { + //remove delete button on the previous row + document.getElementById('delete'+rownum+'.'+(appnum-1)).style.display = 'none'; + } + rownum++; + var next_row = document.getElementById('row'+rownum); // always exists + payment_row.parentNode.insertBefore(tr_app, next_row); + +} + +%# for error handling--ugly, but the alternative is translating the whole +%# process of creating rows into Mason +var row_array = <% encode_json(\@rows) %>; +function preload() { + var rownum; + var appnum; + for (rownum=0; rownum < row_array.length; rownum++) { + if ( row_array[rownum].length ) { + var enable = document.getElementById('enable_app'+rownum); + enable.checked = true; + var preload_row = function(r) {//continuation from toggle_application_row + for (appnum=0; appnum < row_array[r].length; appnum++) { + this_app = row_array[r][appnum]; + var x = r + '.' + appnum; + //set invnum + var select_invnum = document.getElementById('invnum'+x); + focus_app_invnum.call(select_invnum); + for (i=0; i<select_invnum.options.length; i++) { + if (select_invnum.options[i].value == this_app.invnum) { + select_invnum.selectedIndex = i; + } + } + choose_app_invnum.call(select_invnum); + //set amount + var input_amount = document.getElementById('amount'+x); + input_amount.value = this_app.amount; + + //set error + var span_error = document.getElementById('error'+x); + span_error.innerHTML = this_app.error; + change_app_amount.call(input_amount); //creates next row + } //for appnum + }; //preload_row function + toggle_application_row.call(enable, null, preload_row); + } // if row_array[rownum].length + } //for rownum +} + </SCRIPT> <% include('/elements/xmlhttp.html', @@ -57,21 +334,26 @@ function select_discount_term(row, prefix) { <FORM ACTION="process/batch-cust_pay.cgi" NAME="OneTrueForm" METHOD="POST" onsubmit="document.OneTrueForm.btnsubmit.disabled=true;window.onbeforeunload = null;"> <!-- <B>Batch</B> <INPUT TYPE="text" NAME="paybatch"><BR><BR> --> +<& /elements/xmlhttp.html, + url => $p.'misc/xmlhttp-cust_bill-search.html', + subs => ['custnum_search_open'] +&> -<% include( "/elements/customer-table.html", - name_singular => 'payment', - 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, - ) -%> +<& /elements/customer-table.html, + name_singular => 'payment', + header => \@header, + fields => \@fields, + type => \@types, + align => \@align, + size => \@sizes, + color => \@colors, + param => \%param, + footer => \@footer, + footer_align => \@footer_align, + onchange => \@onchange, + custnum_update_callback => 'custnum_update_callback', + add_row_callback => 'add_row_callback', +&> <BR> <INPUT TYPE="button" VALUE="Post payment batch" name="btnsubmit" onclick="window.onbeforeunload = null; document.OneTrueForm.submit(); this.disabled = true;"> @@ -96,18 +378,20 @@ die "access denied" my $conf = new FS::Conf; my $money_char = $conf->config('money_char') || '$'; -my @header = ( '', 'Amount', 'Check #' ); -my @fields = ( sub { "$money_char" }, 'paid', 'payinfo' ); -my @types = ( 'immutable', '', '' ); -my @align = ( 'c', 'r', 'r' ); -my @sizes = ( 0, 8, 10 ); -my @colors = ( '', '', '' ); +my @header = ( 'Amount', 'Check #' ); +my @fields = ( 'paid', 'payinfo' ); +my @types = ( '', '' ); +my @align = ( 'r', 'r' ); +my @sizes = ( 8, 10 ); +my @colors = ( '', '' ); my %param = (); -my @footer = ( "$money_char", '_TOTAL', '' ); -my @footer_align = ( 'c', 'r', 'r' ); -my $custnum_update_callback = ''; +my @footer = ( '_TOTAL', '' ); +my @footer_align = ( 'r', 'r' ); +my @onchange = ( '', '' );; +my $use_discounts = ''; if ( FS::Record->scalar_sql('SELECT COUNT(*) FROM part_pkg_discount') ) { + #push @header, 'Discount'; push @header, ''; push @fields, 'discount_term'; push @types, 'immutable'; @@ -116,9 +400,21 @@ if ( FS::Record->scalar_sql('SELECT COUNT(*) FROM part_pkg_discount') ) { push @colors, ''; push @footer, ''; push @footer_align, ''; - $custnum_update_callback = 'select_discount_term'; + push @onchange, ''; + $use_discounts = 'Y'; } +push @header, 'Allocate'; +push @fields, 'enable_app'; +push @types, 'checkbox'; +push @align, 'c'; +push @sizes, '0'; +push @colors, ''; +push @footer, ''; +push @footer_align, ''; +push @onchange, 'toggle_application_row'; + +#push @header, 'Error'; push @header, ''; push @fields, 'error'; push @types, 'immutable'; @@ -127,7 +423,34 @@ push @sizes, '0'; push @colors, '#ff0000'; push @footer, ''; push @footer_align, ''; +push @onchange, ''; $m->comp('/elements/handle_uri_query'); +# set up for preloading +my @rows; +my @row_errors; +if ( $cgi->param('error') ) { + my $param = $cgi->Vars; + my $enum = 0; #errors numbered separately + for( my $row = 0; exists($param->{"custnum$row"}); $row++ ) { + $rows[$row] = []; + $row_errors[$row] = $param->{"error$enum"}; + $enum++; + for( my $app = 0; exists($param->{"invnum$row.$app"}); $app++ ) { + next if !$param->{"invnum$row.$app"}; + my %this_app = map { $_ => ($param->{$_.$row.'.'.$app} || '') } + qw( invnum amount ); + $this_app{'error'} = $param->{"error$enum"} || ''; + $param->{"error$enum"} = ''; # don't pass this error through + $rows[$row][$app] = \%this_app; + $enum++; + } + } + for( my $row = 0; $row < @row_errors; $row++ ) { + $param->{"error$row"} = $row_errors[$row]; + } +} +#warn Dumper {rows => \@rows, row_errors => \@row_errors }; + </%init> diff --git a/httemplate/misc/cancel_pkg.html b/httemplate/misc/cancel_pkg.html index 42cc56dfe..f9a46a898 100755 --- a/httemplate/misc/cancel_pkg.html +++ b/httemplate/misc/cancel_pkg.html @@ -13,22 +13,53 @@ % my $date_init = 0; % if ($method eq 'expire' || $method eq 'adjourn' || $method eq 'resume') { % $submit =~ /^(\w*)\s/; -<& /elements/tr-input-date-field.html, { - 'name' => 'date', - 'value' => $date, - 'label' => mt("$1 package on"), - 'format' => $date_format, -} &> + <& /elements/tr-input-date-field.html, { + 'name' => 'date', + 'value' => $date, + 'label' => mt("$1 package on"), + 'format' => $date_format, + } &> % $date_init = 1; % } -% unless ( $method eq 'resume' ) { #the only one that doesn't need a reason -<& /elements/tr-select-reason.html, - 'field' => 'reasonnum', - 'reason_class' => $class, - 'curr_value' => $reasonnum, - 'control_button' => "document.getElementById('confirm_cancel_pkg_button')", -&> +% if ($method eq 'uncancel' ) { +% +% #XXX customer also requested setup +% # setup: what usefulness is changing or blanking this? re-charge setup fee? +% # an option that says that would be better if that's what we want to do + +% # last_bill: isn't this informational? what good would editing it do? +% # something about invoice display? + <& /elements/tr-input-date-field.html, { + 'name' => 'last_bill', + 'value' => ( $cgi->param('last_bill') || $cust_pkg->get('last_bill') ), + 'label' => mt("Last bill date"), + 'format' => $date_format, + } &> + + <& /elements/tr-input-date-field.html, { + 'name' => 'bill', + 'value' => ( $cgi->param('bill') || $cust_pkg->get('bill') ), + 'label' => mt("Next bill date"), + 'format' => $date_format, + } &> + + <& /elements/tr-checkbox.html, + 'label' => mt("Uncancel even if a service can't be re-provisioned"), + 'field' => 'svc_not_fatal', + 'value' => 'Y', + &> + +% $date_init = 1; +% } + +% unless ( $method eq 'resume' || $method eq 'uncancel' ) { + <& /elements/tr-select-reason.html, + field => 'reasonnum', + reason_class => $class, + curr_value => $reasonnum, + control_button => "document.getElementById('confirm_cancel_pkg_button')", + &> % } % if ( $method eq 'adjourn' || $method eq 'suspend' ) { @@ -49,26 +80,27 @@ % ? str2time($cgi->param('resume_date')) % : $cust_pkg->get('resume'); -<& /elements/tr-input-date-field.html, { - 'name' => 'resume_date', - 'value' => $resume_date, - 'label' => mt('Unsuspend on'), - 'format' => $date_format, - 'noinit' => $date_init, -} &> + <& /elements/tr-input-date-field.html, { + 'name' => 'resume_date', + 'value' => $resume_date, + 'label' => mt('Unsuspend on'), + 'format' => $date_format, + 'noinit' => $date_init, + } &> % } </TABLE> <BR> <INPUT TYPE="submit" NAME="submit" ID="confirm_cancel_pkg_button" VALUE="<% mt($submit) |h %>" - <% $method ne 'resume' ? 'DISABLED' : '' %>> + <% $method !~ /^(resume|uncancel)$/ ? 'DISABLED' : '' %>> </FORM> </BODY> </HTML> <%init> +use Date::Parse qw(str2time); my $conf = new FS::Conf; my $date_format = $conf->config('date_format') || '%m/%d/%Y'; @@ -111,6 +143,10 @@ if ($method eq 'cancel') { $class = ''; $submit = 'Unsuspend Later'; $right = 'Unsuspend customer package'; #later? +} elsif ( $method eq 'uncancel') { + $class = ''; + $submit = 'Un-Cancel'; + $right = 'Un-cancel customer package'; #later? } else { die 'illegal query (unknown method param)'; } @@ -119,6 +155,7 @@ my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right($right); my $title = ucfirst($method) . ' Package'; +$title =~ s/Uncancel/Un-cancel/; my $cust_pkg = qsearchs('cust_pkg', {'pkgnum' => $pkgnum}) or die "Unknown pkgnum: $pkgnum"; diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi index dcd033ff2..a277ba407 100644 --- a/httemplate/misc/cust-part_pkg.cgi +++ b/httemplate/misc/cust-part_pkg.cgi @@ -1,11 +1,19 @@ <% objToJson( \@return ) %> <%init> -my( $custnum, $classnum ) = $cgi->param('arg'); +my( $custnum, $prospectnum, $classnum ) = $cgi->param('arg'); -#XXX i guess i should be agent-virtualized. cause "packages a customer can -#order" is such a huge deal -my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); + +my $agent; +if ( $custnum ) { + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) + or die 'unknown custnum'; + $agent = $cust_main->agent; +} else { + my $prospect_main = qsearchs('prospect_main', {'prospectnum'=>$prospectnum} ) + or die 'unknown prospectnum'; + $agent = $prospect_main->agent; +} my %hash = ( 'disabled' => '' ); if ( $classnum > 0 ) { @@ -19,7 +27,7 @@ my @part_pkg = qsearch({ 'hashref' => \%hash, 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( 'null'=>1 ). - ' AND '. FS::part_pkg->agent_pkgs_sql( $cust_main->agent ), + ' AND '. FS::part_pkg->agent_pkgs_sql( $agent ), 'order_by' => 'ORDER BY pkg', }); diff --git a/httemplate/misc/cust_main-cancel.cgi b/httemplate/misc/cust_main-cancel.cgi index 002c0011a..2ae9f1021 100755 --- a/httemplate/misc/cust_main-cancel.cgi +++ b/httemplate/misc/cust_main-cancel.cgi @@ -1,4 +1,4 @@ -<& /elements/header.html, mt("Customer cancelled") &> +<& /elements/header-popup.html, mt("Customer cancelled") &> <SCRIPT TYPE="text/javascript"> window.top.location.reload(); </SCRIPT> diff --git a/httemplate/misc/cust_main-import.cgi b/httemplate/misc/cust_main-import.cgi index 664651069..74f9b4c89 100644 --- a/httemplate/misc/cust_main-import.cgi +++ b/httemplate/misc/cust_main-import.cgi @@ -35,6 +35,7 @@ Import a file containing customer records. <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 + <OPTION VALUE="birthdates-acct_phone_hardware">Birthdates and account, phone and hardware services </SELECT> </TD> </TR> @@ -106,6 +107,9 @@ Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets. <b>External service and phone 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, countrycode, phonenum, sip_password, pin</i> <BR><BR> +<b>Birthdates and account, phone and hardware services</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, birthdate, spouse_birthdate, payinfo, paycvv, paydate, invoicing_list, pkgpart, next_bill_date, username, _password, countrycode, phonenum, sip_password, pin, typenum, ip_addr, hw_addr, serial</i> +<BR><BR> + <%$req%> Required fields <BR><BR> diff --git a/httemplate/misc/cust_main-suspend.cgi b/httemplate/misc/cust_main-suspend.cgi new file mode 100755 index 000000000..61851364e --- /dev/null +++ b/httemplate/misc/cust_main-suspend.cgi @@ -0,0 +1,75 @@ +<& /elements/header-popup.html, mt("Customer suspended") &> + <SCRIPT TYPE="text/javascript"> + window.top.location.reload(); + </SCRIPT> + </BODY> +</HTML> +<%init> + +#false laziness w/cust_main-cancel.cgi + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Suspend customer'); + +my $custnum; +my $adjourn = ''; +if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { + $custnum = $1; + $adjourn = $cgi->param('adjourn'); +} else { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/ || die "Illegal custnum"; + $custnum = $1; +} + +#false laziness w/process/cancel_pkg.html + +#untaint reasonnum +my $reasonnum = $cgi->param('reasonnum'); +$reasonnum =~ /^(-?\d+)$/ || die "Illegal reasonnum"; +$reasonnum = $1; + +if ($reasonnum == -1) { + $reasonnum = { + 'typenum' => scalar( $cgi->param('newreasonnumT') ), + 'reason' => scalar( $cgi->param('newreasonnum' ) ), + }; +} + +#eslaf + +my $cust_main = qsearchs( { + 'table' => 'cust_main', + 'hashref' => { 'custnum' => $custnum }, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +} ); + +my @errors; +if($cgi->param('now_or_later')) { + $adjourn = parse_datetime($adjourn); + if($adjourn) { + #warn "setting adjourn dates on custnum#$custnum\n"; + my @pkgs = $cust_main->unsuspended_pkgs; + @errors = grep {$_} map { $_->suspend( + 'reason' => $reasonnum, + 'date' => $adjourn, + ) } @pkgs; + } + else { + @errors = ("error parsing adjourn date: ".$cgi->param('adjourn')); + } +} +else { + warn "suspending $cust_main"; + @errors = $cust_main->suspend( + 'reason' => $reasonnum, + ); +} +my $error = join(' / ', @errors) if scalar(@errors); + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(1). "suspend_cust.html?". $cgi->query_string ); +} + +</%init> diff --git a/httemplate/misc/cust_main-unsuspend.cgi b/httemplate/misc/cust_main-unsuspend.cgi new file mode 100755 index 000000000..eb4a2c8f8 --- /dev/null +++ b/httemplate/misc/cust_main-unsuspend.cgi @@ -0,0 +1,56 @@ +<& /elements/header-popup.html, mt("Customer unsuspended") &> + <SCRIPT TYPE="text/javascript"> + window.top.location.reload(); + </SCRIPT> + </BODY> +</HTML> +<%init> + +#false laziness w/cust_main-cancel.cgi + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Unsuspend customer'); + +my $custnum; +my $resume = ''; +if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { + $custnum = $1; + $resume = $cgi->param('resume'); +} else { + my($query) = $cgi->keywords; + $query =~ /^(\d+)$/ || die "Illegal custnum"; + $custnum = $1; +} + +my $cust_main = qsearchs( { + 'table' => 'cust_main', + 'hashref' => { 'custnum' => $custnum }, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, +} ); + +my @errors; +if($cgi->param('now_or_later')) { + $resume = parse_datetime($resume); + if($resume) { + #warn "setting resume dates on custnum#$custnum\n"; + my @pkgs = $cust_main->suspended_pkgs; + @errors = grep {$_} map { $_->unsuspend( + 'date' => $resume, + ) } @pkgs; + } + else { + @errors = ("error parsing adjourn date: ".$cgi->param('adjourn')); + } +} +else { + warn "unsuspending $cust_main"; + @errors = $cust_main->unsuspend; +} +my $error = join(' / ', @errors) if scalar(@errors); + +if ( $error ) { + $cgi->param('error', $error); + print $cgi->redirect(popurl(1). "unsuspend_cust.html?". $cgi->query_string ); +} + +</%init> diff --git a/httemplate/misc/delete-ftp_target.html b/httemplate/misc/delete-ftp_target.html new file mode 100644 index 000000000..c8bd29701 --- /dev/null +++ b/httemplate/misc/delete-ftp_target.html @@ -0,0 +1,18 @@ +% if ( $error ) { +% errorpage($error); +% } else { +<% $cgi->redirect("${p}browse/ftp_target.html") %> +% } +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal targetnum"; +my $targetnum = $1; + +my $target = qsearchs('ftp_target',{'targetnum'=>$targetnum}); +my $error = $target->delete; + +</%init> diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi index 23deba712..f3a31eb3b 100644 --- a/httemplate/misc/download-batch.cgi +++ b/httemplate/misc/download-batch.cgi @@ -1,4 +1,4 @@ -<% $pay_batch->export_batch($format) %><%init> +<% $pay_batch->export_batch(%opt) %><%init> #http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes http_header('Content-Type' => 'text/plain' ); # not necessarily correct... @@ -10,9 +10,14 @@ if ( $cgi->param('batchnum') =~ /^(\d+)$/ ) { die "No batch number (bad URL) \n"; } -my $format; -if ( $cgi->param('format') =~ /^([\w\- ]+)$/ ) { - $format = $1; +my %opt; +if ( $cgi->param('gatewaynum') =~ /^(\d+)$/ ) { + my $gateway = FS::payment_gateway->by_key($1); + die "gatewaynum $1 not found" unless $gateway; + $opt{'gateway'} = $gateway; +} +elsif ( $cgi->param('format') =~ /^([\w\- ]+)$/ ) { + $opt{'format'} = $1; } my $pay_batch = qsearchs('pay_batch', { batchnum => $batchnum } ); diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html index 2332f2028..7aa024a34 100644 --- a/httemplate/misc/order_pkg.html +++ b/httemplate/misc/order_pkg.html @@ -32,6 +32,15 @@ &> % } +% if ( $conf->exists('invoice-unitprice') ) { + <TR> + <TH ALIGN="right"><% mt('Quantity') |h %> </TD> + <TD> + <INPUT TYPE="text" NAME="quantity" SIZE=4 VALUE="<% $quantity %>"> + </TD> + </TR> +% } + <TR> <TH ALIGN="right"><% mt('Start date') |h %> </TD> <TD COLSPAN=6> @@ -163,6 +172,11 @@ if ( $cgi->param('lock_pkgpart') ) { my $pkgpart = $part_pkg ? $part_pkg->pkgpart : scalar($cgi->param('pkgpart')); +my $quantity = 1; +if ( $cgi->param('quantity') =~ /^\s*(\d+)\s*$/ ) { + $quantity = $1; +} + my $format = $date_format. ' %T %z (%Z)'; #false laziness w/REAL_cust_pkg.cgi? my $start_date = ''; if( ! $conf->exists('order_pkg-no_start_date') ) { diff --git a/httemplate/misc/process/batch-cust_pay.cgi b/httemplate/misc/process/batch-cust_pay.cgi index aa371266c..1105af943 100644 --- a/httemplate/misc/process/batch-cust_pay.cgi +++ b/httemplate/misc/process/batch-cust_pay.cgi @@ -1,51 +1,69 @@ -% die "access denied" -% unless $FS::CurrentUser::CurrentUser->access_right('Post payment batch'); -% -% my $param = $cgi->Vars; -% -% #my $paybatch = $param->{'paybatch'}; -% my $paybatch = time2str('webbatch-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); -% -% my @cust_pay = (); -% #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' => $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"}; -% #$row++; -% } -% -% my @errors = FS::cust_pay->batch_insert(@cust_pay); -% my $num_errors = scalar(grep $_, @errors); -% +<%init> +my $DEBUG = 0; +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Post payment batch'); + +my $param = $cgi->Vars; +warn Dumper($param) if $DEBUG; + +#my $paybatch = $param->{'paybatch'}; +my $paybatch = time2str('webbatch-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time); + +my @cust_pay = (); +#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 ( length($custnum) and !$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 + + my $cust_pay = new FS::cust_pay { + '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"}; + next if !$cust_pay; + #$row++; + + # payment applications, if any + my @cust_bill_pay = (); + for ( my $app = 0; exists($param->{"invnum$row.$app"}); $app++ ) { + next if !$param->{"invnum$row.$app"}; + push @cust_bill_pay, new FS::cust_bill_pay { + 'invnum' => $param->{"invnum$row.$app"}, + 'amount' => $param->{"amount$row.$app"} + }; + } + $cust_pay->set('apply_to', \@cust_bill_pay) if scalar(@cust_bill_pay) > 0; + + push @cust_pay, $cust_pay; + +} + +my @errors = FS::cust_pay->batch_insert(@cust_pay); +my $num_errors = scalar(grep $_, @errors); +</%init> % if ( $num_errors ) { % % $cgi->param('error', "$num_errors error". ($num_errors>1 ? 's' : ''). @@ -65,4 +83,3 @@ % <% $cgi->redirect(popurl(3). "search/cust_pay.html?magic=paybatch;paybatch=$paybatch") %> % } - diff --git a/httemplate/misc/process/cancel_pkg.html b/httemplate/misc/process/cancel_pkg.html index 4f8e11b7f..79e489c70 100755 --- a/httemplate/misc/process/cancel_pkg.html +++ b/httemplate/misc/process/cancel_pkg.html @@ -6,19 +6,21 @@ </HTML> <%once> -my %past = ( 'cancel' => 'cancelled', - 'expire' => 'expired', - 'suspend' => 'suspended', - 'adjourn' => 'adjourned', - 'resume' => 'scheduled to resume', +my %past = ( 'cancel' => 'cancelled', + 'expire' => 'expired', + 'suspend' => 'suspended', + 'adjourn' => 'adjourned', + 'resume' => 'scheduled to resume', + 'uncancel' => 'un-cancelled', ); #i'm sure this is false laziness with somewhere, at least w/misc/cancel_pkg.html -my %right = ( 'cancel' => 'Cancel customer package immediately', - 'expire' => 'Cancel customer package later', - 'suspend' => 'Suspend customer package', - 'adjourn' => 'Suspend customer package later', - 'resume' => 'Unsuspend customer package', #later? +my %right = ( 'cancel' => 'Cancel customer package immediately', + 'expire' => 'Cancel customer package later', + 'suspend' => 'Suspend customer package', + 'adjourn' => 'Suspend customer package later', + 'resume' => 'Unsuspend customer package', #later? + 'uncancel' => 'Un-cancel customer package', ); </%once> @@ -26,7 +28,8 @@ my %right = ( 'cancel' => 'Cancel customer package immediately', #untaint method my $method = $cgi->param('method'); -$method =~ /^(cancel|expire|suspend|adjourn|resume)$/ or die "Illegal method"; +$method =~ /^(cancel|expire|suspend|adjourn|resume|uncancel)$/ + or die "Illegal method"; $method = $1; my $past_method = $past{$method}; @@ -39,7 +42,7 @@ $pkgnum =~ /^(\d+)$/ or die "Illegal pkgnum"; $pkgnum = $1; my $date = time; -if ($method eq 'expire' || $method eq 'adjourn' || $method eq 'resume'){ +if ($method eq 'expire' || $method eq 'adjourn' || $method eq 'resume') { #untaint date $date = $cgi->param('date'); #huh? parse_datetime($cgi->param('date')) =~ /^(\d+)$/ or die "Illegal date"; @@ -64,7 +67,7 @@ my $cust_pkg = qsearchs( 'cust_pkg', {'pkgnum'=>$pkgnum} ); #untaint reasonnum my $reasonnum = $cgi->param('reasonnum'); -if ( $method ne 'unsuspend' ) { #i.e. 'resume' +if ( $method !~ /^(unsuspend|uncancel)$/ ) { $reasonnum =~ /^(-?\d+)$/ or die "Illegal reasonnum"; $reasonnum = $1; @@ -76,9 +79,20 @@ if ( $method ne 'unsuspend' ) { #i.e. 'resume' } } +#for uncancel +my $last_bill = + $cgi->param('last_bill') ? parse_datetime($cgi->param('last_bill')) : ''; +my $bill = + $cgi->param('bill') ? parse_datetime($cgi->param('bill')) : ''; + +my $svc_fatal = ( $cgi->param('svc_not_fatal') ne 'Y' ); + my $error = $cust_pkg->$method( 'reason' => $reasonnum, 'date' => $date, 'resume_date' => $resume_date, + 'last_bill' => $last_bill, + 'bill' => $bill, + 'svc_fatal' => $svc_fatal, 'options' => $options, ); diff --git a/httemplate/misc/suspend_cust.html b/httemplate/misc/suspend_cust.html new file mode 100644 index 000000000..b41f36f8c --- /dev/null +++ b/httemplate/misc/suspend_cust.html @@ -0,0 +1,79 @@ +<& /elements/header-popup.html, mt('Suspend customer') &> + +<& /elements/error.html &> + +<FORM NAME="cust_suspend_popup" ACTION="<% popurl(1) %>cust_main-suspend.cgi" METHOD=POST> +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> + + <P ALIGN="center"><B><% mt('Suspend this customer?') |h %></B> + +<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"><% mt('Suspend now') |h %></TD> +</TR> +<TR> + <TD ALIGN="right"> + <INPUT TYPE="radio" NAME="now_or_later" VALUE="1" onclick="toggle(true)" /> + </TD> + <TD ALIGN="left"><% mt('Suspend on date: ') |h %> + <& /elements/input-date-field.html, { + 'name' => 'adjourn', + 'value' => time, + } &> + </TD> +</TR> +</TABLE> +<SCRIPT type="text/javascript"> +function toggle(val) { + document.getElementById("adjourn_text").disabled = !val; + document.getElementById("adjourn_button").style.visibility = + val ? 'visible' : 'hidden'; +} +toggle(false); +</SCRIPT> + +<TABLE BGCOLOR="#cccccc", BORDER="0" CELLSPACING="2" +STYLE="margin-left:auto; margin-right:auto"> +<& /elements/tr-select-reason.html, + 'field' => 'reasonnum', + 'reason_class' => 'C', + 'cgi' => $cgi, + 'control_button' => "document.getElementById('confirm_suspend_cust_button')", +&> + +</TABLE> + +<BR> +<P ALIGN="CENTER"> +<INPUT TYPE="submit" NAME="submit" ID="confirm_suspend_cust_button" VALUE="<% mt('Suspend customer') |h %>" DISABLED> + +<INPUT TYPE="BUTTON" VALUE="<% mt("Don't suspend") |h %>" onClick="parent.cClick();"> + +</FORM> +</BODY> +</HTML> + +<%init> + +#false laziness w/cancel_cust.html + +$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; +my $custnum = $1; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" unless $curuser->access_right('Suspend 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/unsuspend_cust.html b/httemplate/misc/unsuspend_cust.html new file mode 100644 index 000000000..600eb268a --- /dev/null +++ b/httemplate/misc/unsuspend_cust.html @@ -0,0 +1,68 @@ +<& /elements/header-popup.html, mt('Unsuspend customer') &> + +<& /elements/error.html &> + +<FORM NAME="cust_unsuspend_popup" ACTION="<% popurl(1) %>cust_main-unsuspend.cgi" METHOD=POST> +<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> + + <P ALIGN="center"><B><% mt('Unsuspend this customer?') |h %></B> + +<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"><% mt('Unsuspend now') |h %></TD> +</TR> +<TR> + <TD ALIGN="right"> + <INPUT TYPE="radio" NAME="now_or_later" VALUE="1" onclick="toggle(true)" /> + </TD> + <TD ALIGN="left"><% mt('Unsuspend on date: ') |h %> + <& /elements/input-date-field.html, { + 'name' => 'resume', + 'value' => time, + } &> + </TD> +</TR> +</TABLE> +<SCRIPT type="text/javascript"> +function toggle(val) { + document.getElementById("resume_text").disabled = !val; + document.getElementById("resume_button").style.visibility = + val ? 'visible' : 'hidden'; +} +toggle(false); +</SCRIPT> + +<BR> +<P ALIGN="CENTER"> +<INPUT TYPE="submit" NAME="submit" ID="confirm_unsuspend_cust_button" VALUE="<% mt('Unsuspend customer') |h %>"> + +<INPUT TYPE="BUTTON" VALUE="<% mt("Don't unsuspend") |h %>" onClick="parent.cClick();"> + +</FORM> +</BODY> +</HTML> + +<%init> + +#false laziness w/cancel_cust.html + +$cgi->param('custnum') =~ /^(\d+)$/ or die 'illegal custnum'; +my $custnum = $1; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" unless $curuser->access_right('Unsuspend 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/xmlhttp-cust_bill-search.html b/httemplate/misc/xmlhttp-cust_bill-search.html new file mode 100644 index 000000000..46f15d1ab --- /dev/null +++ b/httemplate/misc/xmlhttp-cust_bill-search.html @@ -0,0 +1,18 @@ +<% encode_json(\@return) %> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; +die 'access denied' unless $curuser->access_right('View invoices'); +my @return; +if ( $cgi->param('sub') eq 'custnum_search_open' ) { + my $custnum = $cgi->param('arg'); + #warn "searching invoices for $custnum\n"; + my $cust_main = FS::cust_main->by_key($custnum); + @return = map { + +{ $_->hash, + 'owed' => $_->owed } + } $cust_main->open_cust_bill + if $curuser->agentnums_href->{ $cust_main->agentnum }; +} + +</%init> diff --git a/httemplate/misc/xmlhttp-cust_main-discount_terms.cgi b/httemplate/misc/xmlhttp-cust_main-discount_terms.cgi index 71e2da597..b524e69fc 100644 --- a/httemplate/misc/xmlhttp-cust_main-discount_terms.cgi +++ b/httemplate/misc/xmlhttp-cust_main-discount_terms.cgi @@ -2,15 +2,18 @@ % % 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 ( $custnum =~ /^\d+$/ ) { +% 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 ]; +% if ($cust_main) { +% $return = [ map [ $_, sprintf("%d months", $_) ], +% $cust_main->discount_terms ]; +% } % } % <% objToJson($return) %> diff --git a/httemplate/misc/xmlhttp-cust_main-search.cgi b/httemplate/misc/xmlhttp-cust_main-search.cgi index 68c5bf597..16f7cd2bc 100644 --- a/httemplate/misc/xmlhttp-cust_main-search.cgi +++ b/httemplate/misc/xmlhttp-cust_main-search.cgi @@ -1,9 +1,9 @@ % if ( $sub eq 'custnum_search' ) { % my $custnum = $cgi->param('arg'); % my $return = []; -% if ( $custnum =~ /^(\d+)$/ ) { -% $return = findbycustnum($1,0); -% $return = findbycustnum($1,1) if(!scalar(@$return)); +% if ( $custnum =~ /^(\d+)$/ ) { #should also handle +% # cust_main-agent_custid-format') eq 'ww?d+' +% $return = findbycustnum_or_agent_custid($1); % } <% objToJson($return) %> % } elsif ( $sub eq 'smart_search' ) { @@ -12,15 +12,27 @@ % my @cust_main = smart_search( 'search' => $string, % 'no_fuzzy_on_exact' => 1, #pref? % ); -% my $return = [ map [ $_->custnum, $_->name, $_->balance, $_->ucfirst_status, $_->statuscolor ], @cust_main ]; +% my $return = [ map [ $_->custnum, +% $_->name, +% $_->balance, +% $_->ucfirst_status, +% $_->statuscolor, +% scalar($_->open_cust_bill) +% ], +% @cust_main +% ]; % <% objToJson($return) %> % } elsif ( $sub eq 'invnum_search' ) { % % my $string = $cgi->param('arg'); -% my $inv = qsearchs('cust_bill', { 'invnum' => $string }); -% my $return = $inv ? findbycustnum($inv->custnum,0) : []; +% if ( $string =~ /^(\d+)$/ ) { +% my $inv = qsearchs('cust_bill', { 'invnum' => $1 }); +% my $return = $inv ? findbycustnum($inv->custnum) : []; <% objToJson($return) %> +% } else { #return nothing +[] +% } % } % elsif ( $sub eq 'exact_search' ) { % # XXX possibly should query each element separately @@ -39,22 +51,58 @@ % } <%init> -my $conf = new FS::Conf; - my $sub = $cgi->param('sub'); -sub findbycustnum{ - my $custnum = shift; - my $agent = shift; - my $hashref = { 'custnum' => $custnum }; - $hashref = { 'agent_custid' => $custnum } if $agent; - my $c = qsearchs({ - 'table' => 'cust_main', - 'hashref' => $hashref, - 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, - }); - return [ $c->custnum, $c->name, $c->balance, $c->ucfirst_status, $c->statuscolor ] - if $c; - []; +sub findbycustnum { + + my $c = qsearchs({ + 'table' => 'cust_main', + 'hashref' => { 'custnum' => shift }, + 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql, + }) or return []; + + [ $c->custnum, + $c->name, + $c->balance, + $c->ucfirst_status, + $c->statuscolor, + scalar($c->open_cust_bill) + ]; } + +sub findbycustnum_or_agent_custid { + my $num = shift; + + my @or = ( 'agent_custid = ?' ); + my @param = ( $num ); + + if ( $num =~ /^\d+$/ && $num <= 2147483647 ) { #need a bigint custnum? wow + my $conf = new FS::Conf; + if ( $conf->exists('cust_main-default_agent_custid') ) { + push @or, "( agent_custid IS NULL AND custnum = $num )"; + } else { + push @or, "custnum = $num"; + } + } + + my $extra_sql = ' WHERE '. $FS::CurrentUser::CurrentUser->agentnums_sql. + ' AND ( '. join(' OR ', @or). ' )'; + + [ map [ $_->custnum, + $_->name, + $_->balance, + $_->ucfirst_status, + $_->statuscolor, + scalar($_->open_cust_bill), + ], + + qsearch({ + 'table' => 'cust_main', + 'hashref' => {}, + 'extra_sql' => $extra_sql, + 'extra_param' => \@param, + }) + ]; +} + </%init> |