diff options
-rw-r--r-- | FS/FS/AccessRight.pm | 1 | ||||
-rw-r--r-- | FS/FS/ClientAPI/MyAccount.pm | 14 | ||||
-rw-r--r-- | FS/FS/Conf.pm | 7 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 13 | ||||
-rw-r--r-- | FS/FS/cust_main.pm | 46 | ||||
-rw-r--r-- | FS/FS/svc_acct_rt_transaction.pm | 260 | ||||
-rw-r--r-- | FS/MANIFEST | 2 | ||||
-rw-r--r-- | FS/t/svc_acct_rt_transaction.t | 5 | ||||
-rw-r--r-- | fs_selfservice/FS-SelfService/cgi/myaccount.html | 35 | ||||
-rw-r--r-- | htetc/handler.pl | 1 | ||||
-rw-r--r-- | httemplate/elements/menu.html | 2 | ||||
-rw-r--r-- | httemplate/misc/batch-cust_pay.html | 379 | ||||
-rw-r--r-- | httemplate/misc/elements/customer-table.html | 387 | ||||
-rw-r--r-- | httemplate/misc/process/timeworked.html | 47 | ||||
-rwxr-xr-x | httemplate/misc/timeworked.html | 77 | ||||
-rw-r--r-- | httemplate/search/timeworked.html | 74 | ||||
-rw-r--r-- | httemplate/view/cust_main/tickets.html | 27 |
17 files changed, 980 insertions, 397 deletions
diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index fb7e538c2..4071e9730 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -203,6 +203,7 @@ tie my %rights, 'Tie::IxHash', ### 'Miscellaneous rights' => [ { rightname=>'Job queue', global=>1 }, + { rightname=>'Time queue', global=>1 }, { rightname=>'Process batches', global=>1 }, { rightname=>'Reprocess batches', global=>1 }, { rightname=>'Import', global=>1 }, #some of these are ag-virt'ed now? give em their own ACLs diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 459558d61..32c37e9d4 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -120,6 +120,12 @@ sub customer_info { $return{balance} = $cust_main->balance; + $return{tickets} = [ ($cust_main->tickets) ]; + use Data::Dumper; + open(MYFILE, ">>/tmp/debugger"); + print MYFILE Dumper($return{tickets}); + close MYFILE; + my @open = map { { invnum => $_->invnum, @@ -149,6 +155,14 @@ sub customer_info { $return{'postal_invoicing'} = 0 < ( grep { $_ eq 'POST' } $cust_main->invoicing_list ); + if (scalar($conf->config('support_packages'))) { + my $support = 0; + foreach ($cust_main->support_services) { + $support += $_->svc_x->seconds; + } + $return{support_time} = (($support < 0) ? '-' : '' ). int(abs($support)/3600)."h".sprintf("%02d",(abs($support)%3600)/60)."m"; + } + } elsif ( $session->{'svcnum'} ) { #no customer record my $svc_acct = qsearchs('svc_acct', { 'svcnum' => $session->{'svcnum'} } ) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 7f64058b8..e1fa0517a 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -2047,6 +2047,13 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'support_packages', + 'section' => '', + 'description' => 'A list of packages eligible for RT ticket time transfer', + 'type' => 'textarea', + }, + ); 1; diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index b7e754573..da264fa05 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -988,6 +988,19 @@ sub tables_hashref { 'index' => [ ['username'], ['domsvc'] ], }, + 'svc_acct_rt_transaction' => { + 'columns' => [ + 'svcrtid', 'int', '', '', '', '', + 'svcnum', 'int', '', '', '', '', + 'transaction_id', 'int', '', '', '', '', + '_date', @date_type, '', '', + 'seconds', 'int', '', '', '', '', #uhhhh + ], + 'primary_key' => 'svcrtid', + 'unique' => [], + 'index' => [ ['svcnum', 'transaction_id'] ], + }, + #'svc_charge' => { # 'columns' => [ # 'svcnum', 'int', '', '', diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index f437abe41..afcba0874 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -4620,6 +4620,52 @@ sub cust_statuscolor { $statuscolor{$self->cust_status}; } +=item tickets + +Returns an array of hashes representing the customer's RT tickets. + +=cut + +sub tickets { + my $self = shift; + + my $num = $conf->config('cust_main-max_tickets') || 10; + my @tickets = (); + + unless ( $conf->config('ticket_system-custom_priority_field') ) { + + @tickets = @{ FS::TicketSystem->customer_tickets($self->custnum, $num) }; + + } else { + + foreach my $priority ( + $conf->config('ticket_system-custom_priority_field-values'), '' + ) { + last if scalar(@tickets) >= $num; + push @tickets, + @{ FS::TicketSystem->customer_tickets( $self->custnum, + $num - scalar(@tickets), + $priority, + ) + }; + } + } + (@tickets); +} + +# Return services representing svc_accts in customer support packages +sub support_services { + my $self = shift; + my %packages = map { $_ => 1 } $conf->config('support_packages'); + + grep { $_->pkg_svc && $_->pkg_svc->primary_svc eq 'Y' } + grep { $_->part_svc->svcdb eq 'svc_acct' } + map { $_->cust_svc } + grep { exists $packages{ $_->pkgpart } } + $self->ncancelled_pkgs; + +} + =back =head1 CLASS METHODS diff --git a/FS/FS/svc_acct_rt_transaction.pm b/FS/FS/svc_acct_rt_transaction.pm new file mode 100644 index 000000000..0fb64456b --- /dev/null +++ b/FS/FS/svc_acct_rt_transaction.pm @@ -0,0 +1,260 @@ +package FS::svc_acct_rt_transaction; + +use strict; +use vars qw( @ISA ); +use FS::Record qw( qsearch qsearchs dbh ); + +@ISA = qw(FS::Record); + +=head1 NAME + +FS::svc_acct_rt_transaction - Object methods for svc_acct_rt_transaction records + +=head1 SYNOPSIS + + use FS::svc_acct_rt_transaction; + + $record = new FS::svc_acct_rt_transaction \%hash; + $record = new FS::svc_acct_rt_transaction { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::svc_acct_rt_transaction object represents an application of time +from a rt transaction to a svc_acct. FS::svc_acct_rt_transaction inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item svcrtid - primary key + +=item svcnum - the svcnum of the svc_acct to which the time applies + +=item transaction_id - the id of the rt transtaction from which the time applies + +=item seconds - the amount of time which applies + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new svc_acct_rt_transaction. To add the example to the database, see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I<hash> method. + +=cut + +sub table { 'svc_acct_rt_transaction'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +sub insert { + my( $self, %options ) = @_; + + 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 $error = $self->SUPER::insert($options{options} ? %{$options{options}} : ()); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + my $svc_acct = qsearchs('svc_acct', {'svcnum' => $self->svcnum}); + unless ($svc_acct) { + $dbh->rollback if $oldAutoCommit; + return "Can't find svc_acct " . $self->svcnum; + } + + my $error = $svc_acct->decrement_seconds($self->seconds); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error incrementing service seconds: $error"; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + + +=item delete + +Delete this record from the database. + +=cut + +sub delete { + my $self = shift; + + 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 $error = $self->SUPER::delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + my $svc_acct = qsearchs('svc_acct', {'svcnum' => $self->svcnum}); + unless ($svc_acct) { + $dbh->rollback if $oldAutoCommit; + return "Can't find svc_acct " . $self->svcnum; + } + + my $error = $svc_acct->increment_seconds($self->seconds); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "Error incrementing service seconds: $error"; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; + +} + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +=item check + +Checks all fields to make sure this is a valid svc_acct_rt_transaction. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +sub check { + my $self = shift; + + my ($selfref) = $self->hashref; + + my $error = + $self->ut_numbern('svcrtid') + || $self->ut_numbern('svcnum') + || $self->ut_number('transaction_id') + || $self->ut_numbern('_date') + || $self->ut_snumber('seconds') + ; + return $error if $error; + + $self->_date(time) unless $self->_date; + + if ($selfref->{custnum}) { + my $conf = new FS::Conf; + my %packages = map { $_ => 1 } $conf->config('support_packages'); + my $cust_main = qsearchs('cust_main',{ 'custnum' => $selfref->{custnum} } ); + return "Invalid custnum: " . $selfref->{custnum} unless $cust_main; + + my (@svcs) = map { $_->svcnum } $cust_main->support_services; + return "svcnum ". $self->svcnum. " invalid for custnum ".$selfref->{custnum} + unless (!$self->svcnum || scalar(grep { $_ == $self->svcnum } @svcs)); + + $self->svcnum($svcs[0]) unless $self->svcnum; + return "Can't find support service for custnum ".$selfref->{custnum} + unless $self->svcnum; + } + + $self->SUPER::check; +} + +=item batch_insert SVC_ACCT_RT_TRANSACTION_OBJECT, ... + +Class method which inserts multiple time applications. Takes a list of +FS::svc_acct_rt_transaction objects. If there is an error inserting any +application, the entire transaction is rolled back, i.e. all time is applied +or none is. + +For example: + + my $errors = FS::svc_acct_rt_transaction->batch_insert(@transactions); + if ( $error ) { + #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 $error; + foreach (@_) { + $error = $_->insert; + last if $error; + } + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + } else { + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + } + + $error; + +} + +=back + +=head1 BUGS + +Possibly the delete method or others. + +=head1 SEE ALSO + +L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/MANIFEST b/FS/MANIFEST index c30cd1521..07b1eabf8 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -388,3 +388,5 @@ FS/cust_pkg_option.pm t/cust_pkg_option.t FS/conf.pm t/conf.t +FS/svc_acct_rt_transaction.pm +t/svc_acct_rt_transaction.t diff --git a/FS/t/svc_acct_rt_transaction.t b/FS/t/svc_acct_rt_transaction.t new file mode 100644 index 000000000..d9958317e --- /dev/null +++ b/FS/t/svc_acct_rt_transaction.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::svc_acct_rt_transaction; +$loaded=1; +print "ok 1\n"; diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html index 546ca1112..ef0740fd6 100644 --- a/fs_selfservice/FS-SelfService/cgi/myaccount.html +++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html @@ -36,6 +36,41 @@ Hello <%= $name %>!<BR><BR> } %> +<%= + if ( defined($support_time) ) { + $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'. + '<TR><TH BGCOLOR="#ff6666">Support Time Remaining</TH></TR>'. + "<TR><TD>$support_time</TD></TR><BR><BR>"; + } +%> + +<%= + if ( @tickets ) { + $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'. + '<TR><TH BGCOLOR="#ff6666" COLSPAN=5>Open Tickets</TH></TR>'. + '<TR><TH>#</TH><TH>Subject</TH><TH>Priority</TH><TH>Queue</TH>'. + '<TH>Status</TH></TR>'; + my $col1 = "ffffff"; + my $col2 = "dddddd"; + my $col = $col1; + + foreach my $ticket ( @tickets ) { + my $td = qq!<TD BGCOLOR="#$col">!; + $OUT .= + "<TR>$td". $ticket->{'id'}. "</TD>". + $td. $ticket->{'subject'}. "</TD>". + $td. $ticket->{'priority'}. "</TD>". + $td. $ticket->{'name'}. "</TD>". + $td. $ticket->{'status'}. "</TD>". + '</TR>'; + $col = $col eq $col1 ? $col2 : $col1; + } + $OUT .= '</TABLE>'; + } else { + $OUT .= ''; + } +%> + </TD></TR></TABLE> <HR> <FONT SIZE="-2">powered by <a href="http://www.sisd.com/freeside">freeside</a></FONT> diff --git a/htetc/handler.pl b/htetc/handler.pl index 25962412b..c5873a878 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -169,6 +169,7 @@ sub handler use FS::session; use FS::svc_acct; use FS::svc_acct_pop qw(popselector); + use FS::svc_acct_rt_transaction; use FS::svc_domain; use FS::svc_forward; use FS::svc_www; diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 616900c2d..455c7b364 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -214,6 +214,8 @@ $tools_menu{'Process payment batches'} = [ $fsurl.'search/pay_batch.cgi?magic=_d if $conf->exists('batch-enable') && $curuser->access_right('Process batches'); $tools_menu{'Job Queue'} = [ $fsurl.'search/queue.html', 'View pending job queue' ] if $curuser->access_right('Job queue'); +$tools_menu{'Time Queue'} = [ $fsurl.'search/timeworked.html', 'View pending support time' ] + if $curuser->access_right('Time queue'); $tools_menu{'Importing'} = [ \%tools_importing, 'Import tools' ] if $curuser->access_right('Import'); $tools_menu{'Exporting'} = [ \%tools_exporting, 'Export tools' ] diff --git a/httemplate/misc/batch-cust_pay.html b/httemplate/misc/batch-cust_pay.html index d85f3b6c3..f2f446001 100644 --- a/httemplate/misc/batch-cust_pay.html +++ b/httemplate/misc/batch-cust_pay.html @@ -1,8 +1,5 @@ <% include("/elements/header.html", 'Quick payment entry', - menubar( - 'Main Menu' => $p, #popurl(1), - ), - ( $cgi->param('error') ? '' : 'onload="addRow()"' ), + menubar( 'Main Menu' => $p ), ) %> % if ( $cgi->param('error') ) { @@ -16,284 +13,13 @@ <!-- <B>Batch</B> <INPUT TYPE="text" NAME="paybatch"><BR><BR> --> -<SCRIPT TYPE="text/javascript"> - - function clearhint_custnum() { - - //this.style.color = '#000000'; - - if ( this.value == 'Not found' || this.value == 'Multiple' ) { - this.value = ''; - this.style.color = '#000000'; - } - - } - - function clearhint_customer() { - - 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'; - - } - - } - - 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('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 ); - - } - - function select_customer() { - - var custnum = this.options[this.selectedIndex].value; - var customer = this.options[this.selectedIndex].text; - - 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> - -<TR> - <TH>Cust #</TH> - <TH>Customer</TH> - <TH>Amount</TH> - <TH>Check #</TH> - <TH BGCOLOR="#e8e8e8"></TH> -</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> +<% include( "elements/customer-table.html", + header => [ '', 'Amount', 'Check #', '' ], + fields => [ sub {'$'}, 'paid', 'payinfo', 'error', ], + types => [ 'immutable', '', '', 'immutable', ], + sizes => [ 0, 8, 10, 0, ], + param => { () }, + ) %> <!-- <BR> <INPUT TYPE="button" VALUE="TEST addrow" onclick="addRow()"> --> @@ -302,94 +28,5 @@ <INPUT TYPE="submit" NAME="submit" VALUE="Post payment batch"> </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/elements/customer-table.html b/httemplate/misc/elements/customer-table.html new file mode 100644 index 000000000..fc298b03e --- /dev/null +++ b/httemplate/misc/elements/customer-table.html @@ -0,0 +1,387 @@ +% # options example... +% # +% # #listrefs... +% # 'header' => [ '#', 'Item' ], +% # 'fields' => [ +% # 'column', +% # sub { my ($row,$param) = @_; $param->{"column$row"}; }, +% # ], +% # 'sizes' => [], # sizes ignored for immutable +% # 'types' => ['immutable', ''], # immutable or ''/text +% # 'param' => { column0 => 1 }, # preset column of row 0 to 1 +% # + +<SCRIPT TYPE="text/javascript"> + + function clearhint_custnum() { + + if ( this.value == 'Not found' || this.value == 'Multiple' ) { + this.value = ''; + this.style.color = '#000000'; + } + + } + + function clearhint_customer() { + + this.style.color = '#000000'; + + if ( this.value == '(last name or company)' || this.value == 'Not found' ) + this.value = ''; + + } + + function <% $opt{prefix} %>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 ( ( <% $opt{prefix} %>rownum - searchrow ) == 1 ) { + <% $opt{prefix} %>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); + + 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 ) { + customer.value = name; + customer.setAttribute('magic', 'nosearch'); + } else { + customer.value = 'Not found'; + customer.style.color = '#ff0000'; + custnum_obj.style.color = '#ff0000'; + + } + + } + + custnum_search( custnum, search_custnum_update ); + + } + + function <% $opt{prefix} %>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 ( ( <% $opt{prefix} %>rownum - searchrow ) == 1 ) { + <% $opt{prefix} %>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); + + function search_customer_update(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 ) { + + 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'; + + //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 ); + + } + + function select_customer() { + + var custnum = this.options[this.selectedIndex].value; + var customer = this.options[this.selectedIndex].text; + + var searchrow = this.getAttribute('rownum'); + var custnum_obj = document.getElementById('custnum'+searchrow); + var customer_obj = document.getElementById('customer'+searchrow); + + if ( custnum == '' ) { + + } 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="<% $opt{prefix} %>OneTrueTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0> + +<TR> + <TH>Cust #</TH> + <TH>Customer</TH> +% foreach my $header ( @{$opt{header}} ) { + <TH><% $header %></TH> +% } +</TR> +% my $row = 0; +% 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 = <% $opt{prefix} %>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 = <% $opt{prefix} %>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> + +% my $col = 0; +% foreach my $field ( @{$opt{fields}} ) { +% my $value; +% if ( ref($field) eq 'CODE' ) { +% $value = &{$field}($row,$param); +% } else { +% $value = $param->{"$field$row"}; +% } +% my $name = (ref($field) eq 'CODE') ? "column${col}_$row" : "$field$row"; +% my $size = $sizes->[$col] || 10; + <TD> +% if (! $types->[$col] || $types->[$col] eq 'text') { + <INPUT TYPE="text" NAME="<% $name %>" SIZE="<% $size %>" VALUE="<% $value %>" > +% } elsif ($types->[$col] eq 'immutable') { + <% $value %> + <INPUT TYPE="hidden" NAME="<% $name %>" VALUE="<% $value %>" > +% } else { + Cannot represent unknown type: <% $types->[$col] %> +% } + </TD> +% $col++; +% } + + </TR> +% } + + +</TABLE> + +<% include('/elements/xmlhttp.html', + 'url' => $p. 'misc/xmlhttp-cust_main-search.cgi', + 'subs' => [qw( custnum_search smart_search )], + ) +%> + +<SCRIPT TYPE="text/javascript"> + + var <% $opt{prefix} %>rownum = <% $row %>; + + function <% $opt{prefix} %>addRow() { + + var table = document.getElementById('<% $opt{prefix} %>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'+<% $opt{prefix} %>rownum); + custnum_input.setAttribute('id', 'custnum'+<% $opt{prefix} %>rownum); + custnum_input.setAttribute('size', 8); + custnum_input.setAttribute('maxlength', 12); + custnum_input.setAttribute('rownum', <% $opt{prefix} %>rownum); + custnum_input.onfocus = clearhint_custnum; + custnum_input.onchange = <% $opt{prefix} %>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'+<% $opt{prefix} %>rownum); + customer_input.setAttribute('id', 'customer'+<% $opt{prefix} %>rownum); + customer_input.setAttribute('size', 64); + customer_input.setAttribute('value', '(last name or company)' ); + customer_input.setAttribute('rownum', <% $opt{prefix} %>rownum); + customer_input.onfocus = clearhint_customer; + customer_input.onclick = clearhint_customer; + customer_input.onchange = <% $opt{prefix} %>search_customer; + customer_cell.appendChild(customer_input); + + var customer_select = document.createElement('SELECT'); + customer_select.setAttribute('name', 'cust_select'+<% $opt{prefix} %>rownum); + customer_select.setAttribute('id', 'cust_select'+<% $opt{prefix} %>rownum); + customer_select.setAttribute('rownum', <% $opt{prefix} %>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); + +% my $col = 0; +% foreach my $field ( @{$opt{fields}} ) { + var my_cell = document.createElement('TD'); + +% if ($types->[$col] eq 'immutable') { +% my $value; +% if ( ref($field) eq 'CODE' ) { +% $value = &{$field}($row,$param); +% } else { +% $value = $param->{"$field$row"}; +% } + var my_text = document.createTextNode('<% $value %>'); + my_cell.appendChild(my_text); +% } + + var my_input = document.createElement('INPUT'); + my_input.setAttribute('name', '<% $field %>'+<% $opt{prefix} %>rownum); + my_input.setAttribute('size', <% $sizes->[$col] || 10 %>); +% if ($types->[$col] eq 'immutable') { + my_input.setAttribute('type', 'hidden'); +% } + my_cell.appendChild(my_input); + + row.appendChild(my_cell); + +% $col++; +% } + + tablebody.appendChild(row); + + <% $opt{prefix} %>rownum++; + + } + +% unless ($cgi->param('error')) { + <% $opt{prefix} %>addRow(); +% } +</SCRIPT> + +<%init> + +my(%opt) = @_; + +$opt{prefix} = '' unless defined $opt{prefix}; +$opt{prefix} .= '_' if $opt{prefix}; + +my $types = $opt{'types'} ? [ @{$opt{'types'}} ] : []; +my $sizes = $opt{'sizes'} ? [ @{$opt{'sizes'}} ] : []; + +my $param = $opt{param}; +$param = $cgi->Vars if $cgi->param('error'); + +</%init> diff --git a/httemplate/misc/process/timeworked.html b/httemplate/misc/process/timeworked.html new file mode 100644 index 000000000..078d645d1 --- /dev/null +++ b/httemplate/misc/process/timeworked.html @@ -0,0 +1,47 @@ +% if ($error) { +<% $cgi->redirect(popurl(2). "timeworked.html?". $cgi->query_string) %> +% } else { +<% $cgi->redirect(popurl(3). "search/timeworked.html") %> +% } +<%init> + +my %multipliers = map { /^custnum(\d+)$/; ($cgi->param("custnum$1") => $cgi->param("multiplier$1")); } + grep /^custnum\d+$/, $cgi->param; + +my @svc_acct_rt_transaction; +foreach my $transaction ( + map { /^transactionid(\d+)$/; $1; } grep /^transactionid\d+$/, $cgi->param +) { + my $seconds = $cgi->param("seconds$transaction"); + my %seconds = map { $_ => sprintf("%.0f", $seconds * $multipliers{$_}) } + (keys %multipliers); + my $sum = 0; + my $count = 0; + foreach (values %seconds) { + $sum += $_; + $count++; + } + + #fudge in some time if we're close + if (abs($seconds-$sum) <= $count) { + my $adjustment = $seconds-$sum; + foreach (keys %seconds) { # explicitly choose one? + $seconds{$_} += $adjustment; + last; + } + } + + foreach my $customer ( grep {$seconds{$_}} keys %seconds ) { + push @svc_acct_rt_transaction, new FS::svc_acct_rt_transaction { + 'custnum' => $customer, + 'transaction_id' => $transaction, + 'seconds' => $seconds{$customer}, + }; + } + +} + +my $error = FS::svc_acct_rt_transaction->batch_insert(@svc_acct_rt_transaction); +$cgi->param('error', $error) if $error; + +</%init> diff --git a/httemplate/misc/timeworked.html b/httemplate/misc/timeworked.html new file mode 100755 index 000000000..2b288f233 --- /dev/null +++ b/httemplate/misc/timeworked.html @@ -0,0 +1,77 @@ +<% include('/elements/header.html', $title, '' ) %> + +% if ( $cgi->param('error') ) { + <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT> + <BR><BR> +% } + +<FORM NAME="timeworked_form" ACTION="<% popurl(1) %>process/timeworked.html" METHOD=POST> + +<BR><BR> +<% include("elements/customer-table.html", header => [ 'Multiplier' ], + fields => [ 'multiplier' ], + param => { %param }, + ) %> + +<BR> +<INPUT TYPE="submit" NAME="submit" VALUE="<% $title %>"> +<BR> +<BR> + +for transactions/tickets: +<TABLE> + +% foreach ( sort { $a <=> $b } keys %ticket ) { + + <TR><TD><% $_ %></TD><TD><% $ticket{$_} %></TD></TR> + <INPUT TYPE="hidden" NAME="transactionid<% $_ %>" VALUE="1" > + <INPUT TYPE="hidden" NAME="seconds<% $_ %>" VALUE="<% $cgi->param("seconds$_") %>" > + +% } + +</TABLE> +</FORM> +</BODY> +</HTML> + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Time queue'); + +my($svcnum, %ticket, %customers, %param); +my $title = 'Assign Time Worked'; + +RT::Init(); + +my $CurrentUser = RT::CurrentUser->new(); +$CurrentUser->LoadByName($FS::CurrentUser::CurrentUser->username); + +foreach my $id ( map { /^transactionid(\d+)$/; $1; } + grep /^transactionid\d+$/, $cgi->param) { + my $transaction = new RT::Transaction($CurrentUser); + $transaction->Load($id); + my $ticket = new RT::Ticket($CurrentUser); + $ticket->Load($transaction->ObjectId); + $ticket{$id} = $ticket->Subject; + foreach my $customerURI ( + grep { $_->Resolver->{'fstable'} eq 'cust_main' } + grep { $_->Scheme eq 'freeside' } + map { $_->TargetURI } + @{ $ticket->_Links('Base')->ItemsArrayRef } + ) { + $customers{$customerURI->Resolver->AsString} = 1; + } +} + +my $row = 0; +foreach ( keys %customers ) { + my ($number, $name) = split(':', $_, 2); + $param{"custnum$row"} = $number; + $param{"customer$row"} = $name; + $param{"multiplier$row"} = sprintf("%.2f", 1/scalar(keys(%customers))); + $row++; +} + +</%init> + diff --git a/httemplate/search/timeworked.html b/httemplate/search/timeworked.html new file mode 100644 index 000000000..18af74641 --- /dev/null +++ b/httemplate/search/timeworked.html @@ -0,0 +1,74 @@ +<% include( 'elements/search.html', + 'title' => 'Time Worked', + 'menubar' => [ 'Main menu' => $p, ], + 'name' => 'time', + 'html_form' => qq!<FORM NAME="timeForm" ACTION="${p}misc/timeworked.html" METHOD="POST">!, + 'query' => $query, + 'count_query' => $count_query, + 'header' => [ '#', + 'Ticket', + 'Date', + 'Time', + '', # checkbox column + ], + 'fields' => [ sub { shift->[0] }, + sub { shift->[1] }, + sub { shift->[2] }, + sub { my $seconds = shift->[3]; + (($seconds < 0) ? '-' : '') . + concise(duration($seconds)); + }, + sub { + my $row = shift; + my $seconds = $row->[3]; + my $id = $row->[4]; + qq!<INPUT NAME="transactionid$id" TYPE="checkbox" VALUE="1">!. + qq!<INPUT NAME="seconds$id" TYPE="hidden" VALUE="$seconds">!; + }, + ], + 'html_foot' => sub { + '<BR><INPUT TYPE="button" VALUE="select all" onClick="setAll(true)">'. + '<INPUT TYPE="button" VALUE="unselect all" onClick="setAll(false)">'. + '<BR><INPUT TYPE="submit" NAME="action" VALUE="Assign to accounts"><BR>'. + '<SCRIPT TYPE="text/javascript">'. + ' function setAll(setTo) { '. + ' theForm = document.timeForm;'. + ' for (i=0,n=theForm.elements.length;i<n;i++)'. + ' if (theForm.elements[i].name.indexOf("transactionid") != -1)'. + ' theForm.elements[i].checked = setTo;'. + ' }'. + '</SCRIPT>'; + }, + ) + +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Time queue'); + +my @groupby = (); + +my $transactiontime = "CASE transactions.type when 'Set' THEN (to_number(newvalue,'999999')-to_number(oldvalue, '999999')) * 60 ELSE timetaken*60 END"; +push @groupby, "transactions.type"; +push @groupby, "newvalue"; +push @groupby, "oldvalue"; +push @groupby, "timetaken"; + +my $appliedtimeclause = "coalesce (sum(svc_acct_rt_transaction.seconds), 0)"; + +my $appliedtimeselect = "SELECT sum(seconds) FROM svc_acct_rt_transaction where transaction_id = transactions.id"; +push @groupby, "transactions.id"; + +my $wheretimeleft = "($transactiontime != ($appliedtimeselect) OR ($appliedtimeselect) is NULL)"; + +push @groupby, "tickets.id"; +push @groupby, "tickets.subject"; +push @groupby, "transactions.created"; + +my $groupby = join(',', @groupby); + +my $query = "SELECT tickets.id,tickets.subject,to_char(transactions.created, 'Dy Mon DD HH24:MI:SS YYYY'),$transactiontime-$appliedtimeclause,transactions.id FROM transactions JOIN tickets ON transactions.objectid = tickets.id LEFT JOIN svc_acct_rt_transaction on transactions.id = svc_acct_rt_transaction.transaction_id WHERE objecttype='RT::Ticket' AND ((transactions.type='Set' AND field='TimeWorked') OR transactions.type='Comment' OR transactions.type='Correspond') AND ($wheretimeleft) GROUP BY $groupby ORDER BY transactions.created"; +my $count_query = "SELECT count(*) FROM transactions WHERE objecttype='RT::Ticket' AND ((transactions.type='Set' AND field='TimeWorked') OR transactions.type='Comment' OR transactions.type='Correspond') AND ($wheretimeleft)"; + +</%init> diff --git a/httemplate/view/cust_main/tickets.html b/httemplate/view/cust_main/tickets.html index 84cc90299..c4183ae55 100644 --- a/httemplate/view/cust_main/tickets.html +++ b/httemplate/view/cust_main/tickets.html @@ -1,31 +1,6 @@ % % my( $cust_main ) = @_; -% -% my $conf = new FS::Conf; -% my $num = $conf->config('cust_main-max_tickets') || 10; -% -% my @tickets = (); -% unless ( $conf->config('ticket_system-custom_priority_field') ) { -% -% @tickets = -% @{ FS::TicketSystem->customer_tickets($cust_main->custnum, $num) }; -% -% } else { -% -% foreach my $priority ( -% $conf->config('ticket_system-custom_priority_field-values'), '' -% ) { -% last if scalar(@tickets) >= $num; -% push @tickets, -% @{ FS::TicketSystem->customer_tickets( $cust_main->custnum, -% $num - scalar(@tickets), -% $priority, -% ) -% }; -% } -% -% } -% +% my( @tickets ) = $cust_main->tickets; % <A NAME="tickets"><FONT SIZE="+2">Tickets</FONT></A> |