diff options
-rw-r--r-- | Changes.1.5.8 | 5 | ||||
-rw-r--r-- | FS/FS/cust_pay.pm | 60 | ||||
-rw-r--r-- | README.1.5.8 | 2 | ||||
-rw-r--r-- | htetc/global.asa | 3 | ||||
-rw-r--r-- | htetc/handler.pl | 1 | ||||
-rw-r--r-- | httemplate/docs/upgrade10.html | 1 | ||||
-rw-r--r-- | httemplate/index.html | 2 | ||||
-rw-r--r-- | httemplate/misc/batch-cust_pay.html | 414 | ||||
-rw-r--r-- | httemplate/misc/process/batch-cust_pay.cgi | 40 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-cust_main-search.cgi | 21 | ||||
-rwxr-xr-x | httemplate/search/cust_pay.cgi | 104 |
11 files changed, 530 insertions, 123 deletions
diff --git a/Changes.1.5.8 b/Changes.1.5.8 index f8066cc99..2b55c5cdf 100644 --- a/Changes.1.5.8 +++ b/Changes.1.5.8 @@ -16,3 +16,8 @@ - moved to XMLHttpRequest instead of hidden iframe transport for progress bar, should be more efficient and improve compatibility with Konq and maybe other browsers? +- also use XMLHttpRequest for retreiving states rather than send a huge page + for customer add/edit, much faster +- redo account view and edit pages, add ability to edit uid/gid if conf options + for it are turned on +- redo quick payment entry page with ajax magic diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 0f872a4d2..a7d69901f 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -122,12 +122,13 @@ sub insert { $self->custnum($cust_bill->custnum ); } - my $cust_main = $self->cust_main; - my $old_balance = $cust_main->balance; my $error = $self->check; return $error if $error; + my $cust_main = $self->cust_main; + my $old_balance = $cust_main->balance; + $error = $self->SUPER::insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -398,6 +399,61 @@ sub check { $self->SUPER::check; } +=item batch_insert CUST_PAY_OBJECT, ... + +Class method which inserts multiple payments. Takes a list of FS::cust_pay +objects. Returns a list, each element representing the status of inserting the +corresponding payment - empty. If there is an error inserting any payment, the +entire transaction is rolled back, i.e. all payments are inserted or none are. + +For example: + + my @errors = FS::cust_pay->batch_insert(@cust_pay); + my $num_errors = scalar(grep $_, @errors); + if ( $num_errors == 0 ) { + #success; all payments were inserted + } else { + #failure; no payments were inserted. + } + +=cut + +sub batch_insert { + my $self = shift; #class method + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $errors = 0; + + my @errors = map { + my $error = $_->insert; + if ( $error ) { + $errors++; + } else { + $_->cust_main->apply_payments; + } + $error; + } @_; + + if ( $errors ) { + $dbh->rollback if $oldAutoCommit; + } else { + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + } + + @errors; + +} + =item cust_bill_pay Returns all applications to invoices (see L<FS::cust_bill_pay>) for this diff --git a/README.1.5.8 b/README.1.5.8 index fb173650e..209ab3fef 100644 --- a/README.1.5.8 +++ b/README.1.5.8 @@ -1,4 +1,6 @@ +install JSON + install DBIx::DBSchema 0.27 install HTML::Widgets:SelectLayers 0.05 install Business::CreditCard 0.28 diff --git a/htetc/global.asa b/htetc/global.asa index 1a81c4b1c..bb30608a4 100644 --- a/htetc/global.asa +++ b/htetc/global.asa @@ -14,6 +14,7 @@ use Time::Duration; use Tie::IxHash; use URI::Escape; use HTML::Entities; +use JSON; use IO::Handle; use IO::File; use IO::Scalar; @@ -47,7 +48,7 @@ use FS::cust_bill; use FS::cust_bill_pay; use FS::cust_credit; use FS::cust_credit_bill; -use FS::cust_main; +use FS::cust_main qw(smart_search); use FS::cust_main_county; use FS::cust_pay; use FS::cust_pkg; diff --git a/htetc/handler.pl b/htetc/handler.pl index 737e5af0b..851b2e7d2 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -99,6 +99,7 @@ sub handler use Tie::IxHash; use URI::Escape; use HTML::Entities; + use JSON; use IO::Handle; use IO::File; use IO::Scalar; diff --git a/httemplate/docs/upgrade10.html b/httemplate/docs/upgrade10.html index fb51bfb8e..a4ed27170 100644 --- a/httemplate/docs/upgrade10.html +++ b/httemplate/docs/upgrade10.html @@ -9,6 +9,7 @@ If migrating from 1.5.7, see README.1.5.8 instead If migrating from 1.5.0pre6, see README.1.5.7 instead +install JSON install DBD::Pg 1.32, 1.41 or later (not 1.40) (or, if you're using a Perl version before 5.6, you could try installing DBD::Pg 1.22 with <a href="http://420.am/~ivan/DBD-Pg-1.22-fixvercmp.patch">this patch</a> and commenting out the "use DBD::Pg 1.32" at the top of DBIx/DBSchema/DBD/Pg.pm) install DBIx::DBSchema 0.26 install Net::SSH 0.08 diff --git a/httemplate/index.html b/httemplate/index.html index 82a028126..b4b85063e 100644 --- a/httemplate/index.html +++ b/httemplate/index.html @@ -120,7 +120,7 @@ <TABLE CELLSPACING=2 CELLPADDING=0 BORDER=0 WIDTH="100%" BGCOLOR="#eeeeee"> <TR><TH BGCOLOR="#cccccc">Bookkeeping / Collections</TH></TR> <TR><TD> - <BR><A HREF="search/cust_main-quickpay.html">Quick payment entry</A> + <BR><A HREF="misc/batch-cust_pay.html">Quick payment entry</A> <BR> <BR><FORM ACTION="search/cust_main.cgi" METHOD="GET">Credit card # <INPUT TYPE="hidden" NAME="card_on" VALUE="1"><INPUT TYPE="text" NAME="card"><INPUT TYPE="submit" VALUE="Search"></FORM> <FORM ACTION="search/cust_bill.html" METHOD="GET">Invoice # <INPUT TYPE="text" NAME="invnum" SIZE="8"><INPUT TYPE="submit" VALUE="Search"></FORM> diff --git a/httemplate/misc/batch-cust_pay.html b/httemplate/misc/batch-cust_pay.html index b09876b89..ac7f7ffa3 100644 --- a/httemplate/misc/batch-cust_pay.html +++ b/httemplate/misc/batch-cust_pay.html @@ -1,99 +1,234 @@ <%= header( 'Quick payment entry', menubar( - 'Main Menu' => popurl(1), + 'Main Menu' => $p, #popurl(1), + 'Old-style quick payment entry' => + $p. 'search/cust_main-quickpay.html', ), - 'onLoad="addRow()"', + ( $cgi->param('error') ? '' : 'onload="addRow()"' ), ) %> <% if ( $cgi->param('error') ) { %> - <FONT SIZE="+1" COLOR="#ff0000">Error: <%= $cgi->param('error') %></FONT> + <FONT SIZE="+1" COLOR="#ff0000"><%= $cgi->param('error') %></FONT><BR><BR> <% } %> -<SCRIPT TYPE="text/javascript"> - - var rownum = 0; - function addRow() { +<FORM ACTION="process/batch-cust_pay.cgi" NAME="OneTrueForm" METHOD="POST" onsubmit="document.OneTrueForm.submit.disabled=true;"> - var table = document.getElementById('OneTrueTable'); - var tablebody = table.getElementsByTagName('tbody').item(0); +<!-- <B>Batch</B> <INPUT TYPE="text" NAME="paybatch"><BR><BR> --> - var row = document.createElement('TR'); - - var custnum_cell = document.createElement('TD'); - var custnum_input = document.createElement('INPUT'); - custnum_input.setAttribute('name', 'custnum'+rownum); - custnum_input.setAttribute('size', 8); - custnum_input.setAttribute('maxlength', 7); - custnum_input.setAttribute('rownum', rownum); - custnum_input.onchange = search_custnum; - - custnum_cell.appendChild(custnum_input); - row.appendChild(custnum_cell); - - var customer_cell = document.createElement('TD'); - var customer_input = document.createElement('INPUT'); - custnum_input.setAttribute('name', 'customer'+rownum); - customer_input.setAttribute('size', 32); - customer_input.setAttribute('value', '(last name or company)' ); - customer_input.onfocus = clearhint; - customer_input.setAttribute('rownum', rownum); - customer_input.onchange = search_customer; - customer_cell.appendChild(customer_input); - row.appendChild(customer_cell); +<SCRIPT TYPE="text/javascript"> - var paid_cell = document.createElement('TD'); - var paid_text = document.createTextNode('$'); - var paid_input = document.createElement('INPUT'); - paid_input.setAttribute('name', 'paid'+rownum); - paid_input.setAttribute('size', 8); - paid_input.setAttribute('maxlength', 8); - paid_cell.appendChild(paid_text); - paid_cell.appendChild(paid_input); - row.appendChild(paid_cell); + function clearhint_custnum() { - var payinfo_cell = document.createElement('TD'); - var payinfo_input = document.createElement('INPUT'); - payinfo_input.setAttribute('name', 'payinfo'+rownum); - payinfo_input.setAttribute('size', 10); - payinfo_cell.appendChild(payinfo_input); - row.appendChild(payinfo_cell); + //this.style.color = '#000000'; - tablebody.appendChild(row); - - rownum++; + if ( this.value == 'Not found' || this.value == 'Multiple' ) { + this.value = ''; + this.style.color = '#000000'; + } } - function clearhint() { + function clearhint_customer() { - if ( this.value == '(last name or company)' ) + this.style.color = '#000000'; + + if ( this.value == '(last name or company)' || this.value == 'Not found' ) this.value = ''; } function search_custnum() { + this.style.color = '#000000' + + var custnum_obj = this; var searchrow = this.getAttribute('rownum'); + var custnum = this.value; + + if ( custnum == 'searching...' || custnum == 'Not found' || custnum == '' ) + return; + + if ( this.getAttribute('magic') == 'nosearch' ) { + this.setAttribute('magic', ''); + return; + } + + if ( ( rownum - searchrow ) == 1 ) { + addRow(); + } + var customer = document.getElementById('customer'+searchrow); + customer.value = 'searching...'; + customer.disabled = true; + customer.style.color = '#000000'; + customer.style.backgroundColor = '#dddddd'; + + var customer_select = document.getElementById('cust_select'+searchrow); + + //alert('search for custnum ' + custnum + ', row#' + searchrow ); + + customer.style.display = ''; + customer_select.style.display = 'none'; + + function search_custnum_update(name) { + + var name = eval('(' + name + ')' ); + + customer.disabled = false; + customer.style.backgroundColor = '#ffffff'; + + if ( name.length > 0 ) { + //alert('custnum found: ' + name); + customer.value = name; + customer.setAttribute('magic', 'nosearch'); + } else { + customer.value = 'Not found'; + customer.style.color = '#ff0000'; + custnum_obj.style.color = '#ff0000'; - alert('search for custnum row#' + searchrow ); + } + + } + + custnum_search( custnum, search_custnum_update ); } function search_customer() { + var customer_obj = this; var searchrow = this.getAttribute('rownum'); + var customer = this.value; + + if ( customer == 'searching...' || customer == 'Not found' || customer == '' ) + return; + + if ( this.getAttribute('magic') == 'nosearch' ) { + this.setAttribute('magic', ''); + return; + } + + if ( ( rownum - searchrow ) == 1 ) { + addRow(); + } + + var custnum_obj = document.getElementById('custnum'+searchrow); + custnum_obj.value = 'searching...'; + custnum_obj.disabled = true; + custnum_obj.style.color = '#000000'; + custnum_obj.style.backgroundColor = '#dddddd'; + + var customer_select = document.getElementById('cust_select'+searchrow); + + //alert('search for customer ' + customer + ', row#' + searchrow ); + + function search_customer_update(customers) { + + //alert('customers returned: ' + customers); + + var customerArray = eval('(' + customers + ')'); + + custnum_obj.disabled = false; + custnum_obj.style.backgroundColor = '#ffffff'; + + if ( customerArray.length == 0 ) { + + custnum_obj.value = 'Not found'; + custnum_obj.style.color = '#ff0000'; + customer_obj.style.color = '#ff0000'; + + customer_obj.style.display = ''; + customer_select.style.display = 'none'; + + + } else if ( customerArray.length == 1 ) { - alert('search for customer row#' + searchrow ); + //alert('one customer found: ' + customerArray[0]); + + custnum_obj.value = customerArray[0][0]; + customer_obj.value = customerArray[0][1]; + + customer_obj.style.display = ''; + customer_select.style.display = 'none'; + + + } else { + + custnum_obj.value = 'Multiple'; // or something + custnum_obj.style.color = '#ff0000'; + + //alert('multiple customers found, have to create select dropdown'); + + //blank the current list + for ( var i = customer_select.length; i >= 0; i-- ) + customer_select.options[i] = null; + + opt(customer_select, '', 'Multiple customers match "' + customer + '" - select one', '#ff0000'); + + //add the multiple customers + for ( var s = 0; s < customerArray.length; s++ ) + opt(customer_select, customerArray[s][0], customerArray[s][1], '#000000'); + + opt(customer_select, 'cancel', '(Edit search string)', '#000000'); + + customer_obj.style.display = 'none'; + + customer_select.style.display = ''; + + } + + } + + smart_search( customer, search_customer_update ); } -</SCRIPT> + function select_customer() { -<FORM ACTION="<%= $p %>process/batch-cust_pay.cgi" METHOD=POST> + var custnum = this.options[this.selectedIndex].value; + var customer = this.options[this.selectedIndex].text; -<B>Batch <INPUT TYPE="text" NAME="paybatch"><BR><BR> + var searchrow = this.getAttribute('rownum'); + var custnum_obj = document.getElementById('custnum'+searchrow); + var customer_obj = document.getElementById('customer'+searchrow); + + if ( custnum == '' ) { + //this.style.color = '#ff0000'; + + } else if ( custnum == 'cancel' ) { + + custnum_obj.value = ''; + custnum_obj.style.color = '#000000'; + + this.style.display = 'none'; + customer_obj.style.display = ''; + customer_obj.focus(); + + } else { + + + custnum_obj.value = custnum; + custnum_obj.style.color = '#000000'; + + customer_obj.value = customer; + customer_obj.style.color = '#000000'; + + this.style.display = 'none'; + customer_obj.style.display = ''; + + } + + } + + function opt(what,value,text,color) { + var optionName = new Option(text, value, false, false); + optionName.style.color = color; + var length = what.length; + what.options[length] = optionName; + } + +</SCRIPT> <TABLE ID="OneTrueTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0> @@ -102,33 +237,160 @@ <TH>Customer</TH> <TH>Amount</TH> <TH>Check #</TH> + <TH BGCOLOR="#e8e8e8"></TH> </TR> -<!-- -<TR> - <TD> - <INPUT TYPE="text" NAME="custnum0" SIZE=8 MAXLENGTH=7 onChange="alert('search for custnum')" > - </TD> - <TD> - <INPUT TYPE="text" NAME="customer0" SIZE=32 VALUE="(last name or company)" onChange="alert('search for customer')" > - </TD> - <TD> - $<INPUT TYPE="text" NAME="paid0" SIZE=8 MAXLENGTH=8> - </TD> - <TD> - <INPUT TYPE="text" NAME="payinfo" SIZE=10> - </TD> -</TR> ---> +<% my $row = 0; + if ( $cgi->param('error') ) { + my $param = $cgi->Vars; +%> + + <% for ( $row = 0; exists($param->{"custnum$row"}); $row++ ) { %> + + <TR> + + <TD> + <INPUT TYPE="text" NAME="custnum<%= $row %>" ID="custnum<%= $row %>" SIZE=8 MAXLENGTH=12 VALUE="<%= $param->{"custnum$row"} %>" rownum="<%= $row %>"> + <SCRIPT TYPE="text/javascript"> + var custnum_input<%= $row %> = document.getElementById("custnum<%= $row %>"); + custnum_input<%= $row %>.onfocus = clearhint_custnum; + custnum_input<%= $row %>.onchange = search_custnum; + </SCRIPT> + </TD> + + <TD> + <INPUT TYPE="text" NAME="customer<%= $row %>" ID="customer<%= $row %>" SIZE=64 VALUE="<%= $param->{"customer$row"} %>" rownum="<%= $row %>"> + <SCRIPT TYPE="text/javascript"> + var customer_input<%= $row %> = document.getElementById("customer<%= $row %>"); + customer_input<%= $row %>.onfocus = clearhint_customer; + customer_input<%= $row %>.onclick = clearhint_customer; + customer_input<%= $row %>.onchange = search_customer; + </SCRIPT> + <SELECT NAME="cust_select<%= $row %>" ID="cust_select<%= $row %>" rownum="<%= $row %>" STYLE="color:#ff0000; display:none""> + </SELECT> + <SCRIPT TYPE="text/javascript"> + var customer_select<%= $row %> = document.getElementById("cust_select<%= $row %>"); + customer_select<%= $row %>.onchange = select_customer; + </SCRIPT> + </TD> + + <TD> + $<INPUT TYPE="text" NAME="paid<%= $row %>" SIZE=8 MAXLENGTH=8 VALUE="<%= $param->{"paid$row"} %>" > + </TD> + + <TD> + <INPUT TYPE="text" NAME="payinfo<%= $row %>" SIZE=10 VALUE="<%= $param->{"payinfo$row"} %>" > + </TD> + + <TD BGCOLOR="#e8e8e8"> + <% if ( $param->{"error$row"} ) { %> + <FONT SIZE="-1" COLOR="#ff0000">Error: <%= $param->{"error$row"} %></FONT> + <% } %> + </TD> + + </TR> + + <% } %> + +<% } %> </TABLE> -<BR> -<INPUT TYPE="button" VALUE="TEST addrow" onClick="addRow()"> +<!-- <BR> +<INPUT TYPE="button" VALUE="TEST addrow" onclick="addRow()"> --> <BR> -<INPUT TYPE="submit" VALUE="Post payments"> +<INPUT TYPE="submit" NAME="submit" VALUE="Post payments"> </FORM> + + +<%= include('/elements/xmlhttp.html', + 'url' => $p. 'misc/xmlhttp-cust_main-search.cgi', + 'subs' => [qw( custnum_search smart_search )], + ) +%> + +<SCRIPT TYPE="text/javascript"> + + var rownum = <%= $row %>; + + function addRow() { + + var table = document.getElementById('OneTrueTable'); + var tablebody = table.getElementsByTagName('tbody').item(0); + + var row = document.createElement('TR'); + + var custnum_cell = document.createElement('TD'); + + var custnum_input = document.createElement('INPUT'); + custnum_input.setAttribute('name', 'custnum'+rownum); + custnum_input.setAttribute('id', 'custnum'+rownum); + custnum_input.setAttribute('size', 8); + custnum_input.setAttribute('maxlength', 12); + custnum_input.setAttribute('rownum', rownum); + custnum_input.onfocus = clearhint_custnum; + custnum_input.onchange = search_custnum; + custnum_cell.appendChild(custnum_input); + + row.appendChild(custnum_cell); + + var customer_cell = document.createElement('TD'); + + var customer_input = document.createElement('INPUT'); + customer_input.setAttribute('name', 'customer'+rownum); + customer_input.setAttribute('id', 'customer'+rownum); + customer_input.setAttribute('size', 64); + customer_input.setAttribute('value', '(last name or company)' ); + customer_input.setAttribute('rownum', rownum); + customer_input.onfocus = clearhint_customer; + customer_input.onclick = clearhint_customer; + customer_input.onchange = search_customer; + customer_cell.appendChild(customer_input); + + var customer_select = document.createElement('SELECT'); + customer_select.setAttribute('name', 'cust_select'+rownum); + customer_select.setAttribute('id', 'cust_select'+rownum); + customer_select.setAttribute('rownum', rownum); + customer_select.style.color = '#ff0000'; + customer_select.style.display = 'none'; + customer_select.onchange = select_customer; + customer_cell.appendChild(customer_select); + + row.appendChild(customer_cell); + + var paid_cell = document.createElement('TD'); + + var paid_text = document.createTextNode('$'); + paid_cell.appendChild(paid_text); + + var paid_input = document.createElement('INPUT'); + paid_input.setAttribute('name', 'paid'+rownum); + paid_input.setAttribute('size', 8); + paid_input.setAttribute('maxlength', 8); + paid_cell.appendChild(paid_input); + + row.appendChild(paid_cell); + + var payinfo_cell = document.createElement('TD'); + var payinfo_input = document.createElement('INPUT'); + payinfo_input.setAttribute('name', 'payinfo'+rownum); + payinfo_input.setAttribute('size', 10); + payinfo_cell.appendChild(payinfo_input); + row.appendChild(payinfo_cell); + + var error_cell = document.createElement('TD'); + error_cell.style.backgroundColor = '#e8e8e8'; + row.appendChild(error_cell); + + tablebody.appendChild(row); + + rownum++; + + } + +</SCRIPT> + </BODY> </HTML> diff --git a/httemplate/misc/process/batch-cust_pay.cgi b/httemplate/misc/process/batch-cust_pay.cgi new file mode 100644 index 000000000..1cc6c3bad --- /dev/null +++ b/httemplate/misc/process/batch-cust_pay.cgi @@ -0,0 +1,40 @@ +<% + 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++ ) { + push @cust_pay, new FS::cust_pay { + 'custnum' => $param->{"custnum$row"}, + 'paid' => $param->{"paid$row"}, + 'payby' => 'BILL', + 'payinfo' => $param->{"payinfo$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); + + if ( $num_errors ) { + + $cgi->param('error', "$num_errors error". ($num_errors>1 ? 's' : '') ); + + my $erow=0; + $cgi->param('error'. $erow++, shift @errors) while @errors; + + %><%= $cgi->redirect($p.'batch-cust_pay.html?'. $cgi->query_string) + + %><% } else { + + %><%= $cgi->redirect(popurl(3). "search/cust_pay.cgi?magic=paybatch;paybatch=$paybatch") %> + + <% } %> diff --git a/httemplate/misc/xmlhttp-cust_main-search.cgi b/httemplate/misc/xmlhttp-cust_main-search.cgi new file mode 100644 index 000000000..8dbd5a4f2 --- /dev/null +++ b/httemplate/misc/xmlhttp-cust_main-search.cgi @@ -0,0 +1,21 @@ +<% + my $sub = $cgi->param('sub'); + + if ( $sub eq 'custnum_search' ) { + + my $custnum = $cgi->param('arg'); + my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ); + + %>"<%= $cust_main ? $cust_main->name : '' %>" + +<% } elsif ( $sub eq 'smart_search' ) { + + my $string = $cgi->param('arg'); + my @cust_main = smart_search( 'search' => $string ); + my $return = [ map [ $_->custnum, $_->name ], @cust_main ]; + + %><%= objToJson($return) %> + +<% } %> + + diff --git a/httemplate/search/cust_pay.cgi b/httemplate/search/cust_pay.cgi index da3d12523..89da7426a 100755 --- a/httemplate/search/cust_pay.cgi +++ b/httemplate/search/cust_pay.cgi @@ -1,60 +1,78 @@ <% my $title = 'Payment Search Results'; my( $count_query, $sql_query ); - if ( $cgi->param('magic') && $cgi->param('magic') eq '_date' ) { - - my @search = (); + if ( $cgi->param('magic') ) { - if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) { - push @search, "agentnum = $1"; # $search{'agentnum'} = $1; - my $agent = qsearchs('agent', { 'agentnum' => $1 } ); - die "unknown agentnum $1" unless $agent; - $title = $agent->agent. " $title"; - } + my @search = (); + my $orderby; + if ( $cgi->param('magic') eq '_date' ) { - if ( $cgi->param('payby') ) { - $cgi->param('payby') =~ /^(CARD|CHEK|BILL)(-(VisaMC|Amex|Discover))?$/ - or die "illegal payby ". $cgi->param('payby'); - push @search, "cust_pay.payby = '$1'"; - if ( $3 ) { - if ( $3 eq 'VisaMC' ) { - #avoid posix regexes for portability - push @search, - " ( substring(cust_pay.payinfo from 1 for 1) = '4' ". - " OR substring(cust_pay.payinfo from 1 for 2) = '51' ". - " OR substring(cust_pay.payinfo from 1 for 2) = '52' ". - " OR substring(cust_pay.payinfo from 1 for 2) = '53' ". - " OR substring(cust_pay.payinfo from 1 for 2) = '54' ". - " OR substring(cust_pay.payinfo from 1 for 2) = '54' ". - " OR substring(cust_pay.payinfo from 1 for 2) = '55' ". - " ) "; - } elsif ( $3 eq 'Amex' ) { - push @search, - " ( substring(cust_pay.payinfo from 1 for 2 ) = '34' ". - " OR substring(cust_pay.payinfo from 1 for 2 ) = '37' ". - " ) "; - } elsif ( $3 eq 'Discover' ) { - push @search, - " substring(cust_pay.payinfo from 1 for 4 ) = '6011' "; - } else { - die "unknown card type $3"; + + if ( $cgi->param('agentnum') && $cgi->param('agentnum') =~ /^(\d+)$/ ) { + push @search, "agentnum = $1"; # $search{'agentnum'} = $1; + my $agent = qsearchs('agent', { 'agentnum' => $1 } ); + die "unknown agentnum $1" unless $agent; + $title = $agent->agent. " $title"; + } + + if ( $cgi->param('payby') ) { + $cgi->param('payby') =~ /^(CARD|CHEK|BILL)(-(VisaMC|Amex|Discover))?$/ + or die "illegal payby ". $cgi->param('payby'); + push @search, "cust_pay.payby = '$1'"; + if ( $3 ) { + if ( $3 eq 'VisaMC' ) { + #avoid posix regexes for portability + push @search, + " ( substring(cust_pay.payinfo from 1 for 1) = '4' ". + " OR substring(cust_pay.payinfo from 1 for 2) = '51' ". + " OR substring(cust_pay.payinfo from 1 for 2) = '52' ". + " OR substring(cust_pay.payinfo from 1 for 2) = '53' ". + " OR substring(cust_pay.payinfo from 1 for 2) = '54' ". + " OR substring(cust_pay.payinfo from 1 for 2) = '54' ". + " OR substring(cust_pay.payinfo from 1 for 2) = '55' ". + " ) "; + } elsif ( $3 eq 'Amex' ) { + push @search, + " ( substring(cust_pay.payinfo from 1 for 2 ) = '34' ". + " OR substring(cust_pay.payinfo from 1 for 2 ) = '37' ". + " ) "; + } elsif ( $3 eq 'Discover' ) { + push @search, + " substring(cust_pay.payinfo from 1 for 4 ) = '6011' "; + } else { + die "unknown card type $3"; + } } } - } + + my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); + push @search, "_date >= $beginning ", + "_date <= $ending"; + + $orderby = '_date'; + + } elsif ( $cgi->param('magic') eq 'paybatch' ) { + + $cgi->param('paybatch') =~ /^([\w\/\:\-\.]+)$/ + or die "illegal paybatch: ". $cgi->param('paybatch'); - my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); - push @search, "_date >= $beginning ", - "_date <= $ending"; + push @search, "paybatch = '$1'"; + + $orderby = "LOWER(company || ' ' || last || ' ' || first )"; + + } else { + die "unknown search magic: ". $cgi->param('magic'); + } my $search = ''; if ( @search ) { $search = ' WHERE '. join(' AND ', @search); } - + $count_query = "SELECT COUNT(*), SUM(paid) ". "FROM cust_pay LEFT JOIN cust_main USING ( custnum )". $search; - + $sql_query = { 'table' => 'cust_pay', 'select' => join(', ', @@ -63,10 +81,10 @@ FS::UI::Web::cust_sql_fields(), ), 'hashref' => {}, - 'extra_sql' => "$search ORDER BY _date", + 'extra_sql' => "$search ORDER BY $orderby", 'addl_from' => 'LEFT JOIN cust_main USING ( custnum )', }; - + } else { $cgi->param('payinfo') =~ /^\s*(\d+)\s*$/ or die "illegal payinfo"; |