+<& elements/search.html,
+ 'title' => emt('Line items'),
+ 'name' => emt('line items'),
+ 'query' => $query,
+ 'count_query' => $count_query,
+ 'count_addl' => [ $money_char. '%.2f total',
+ $unearned ? ( $money_char. '%.2f unearned revenue' ) : (),
+ ],
+ 'header' => [
+ emt('Description'),
+ ( $unearned
+ ? ( emt('Unearned'), emt('Owed'), emt('Payment date') )
+ : ( emt('Setup charge') )
+ ),
+ ( $use_usage eq 'usage'
+ ? emt('Usage charge')
+ : emt('Recurring charge')
+ ),
+ ( $unearned
+ ? ( emt('Charge start'), emt('Charge end') )
+ : ()
+ ),
+ emt('Invoice'),
+ emt('Date'),
+ FS::UI::Web::cust_header(),
+ ],
+ 'fields' => [
+ sub { $_[0]->pkgnum > 0
+ ? $_[0]->get('pkg') # possibly use override.pkg
+ : $_[0]->get('itemdesc') # but i think this correct
+ },
+ #strikethrough or "N/A ($amount)" or something these when
+ # they're not applicable to pkg_tax search
+ sub { my $cust_bill_pkg = shift;
+ if ( $unearned ) {
+ my $period =
+ $cust_bill_pkg->edate - $cust_bill_pkg->sdate;
+ my $elapsed = $unearned - $cust_bill_pkg->sdate;
+ $elapsed = 0 if $elapsed < 0;
+
+ my $remaining = 1 - $elapsed/$period;
+
+ sprintf($money_char. '%.2f',
+ $remaining * $cust_bill_pkg->recur );
+
+ } else {
+ sprintf($money_char.'%.2f', $cust_bill_pkg->setup );
+ }
+ },
+ ( $unearned
+ ? ( $owed_sub, $payment_date_sub, )
+ : ()
+ ),
+ sub { my $row = shift;
+ my $value = 0;
+ if ( $use_usage eq 'recurring' ) {
+ $value = $row->recur - $row->usage;
+ } elsif ( $use_usage eq 'usage' ) {
+ $value = $row->usage;
+ } else {
+ $value = $row->recur;
+ }
+ sprintf($money_char.'%.2f', $value );
+ },
+ ( $unearned
+ ? ( sub { time2str('%b %d %Y', shift->sdate ) },
+ sub { time2str('%b %d %Y', shift->edate ) },
+ )
+ : ()
+ ),
+ 'invnum',
+ sub { time2str('%b %d %Y', shift->_date ) },
+ \&FS::UI::Web::cust_fields,
+ ],
+ 'sort_fields' => [
+ '',
+ 'setup', #broken in $unearned case i guess
+ ( $unearned ? ('', '') : () ),
+ ( $use_usage eq 'recurring' ? 'recur - usage' :
+ $use_usage eq 'usage' ? 'usage'
+ : 'recur'
+ ),
+ ( $unearned ? ('sdate', 'edate') : () ),
+ 'invnum',
+ '_date',
+ ],
+ 'links' => [
+ #'',
+ '',
+ '',
+ ( $unearned ? ( '', '' ) : () ),
+ '',
+ ( $unearned ? ( '', '' ) : () ),
+ $ilink,
+ $ilink,
+ ( map { $_ ne 'Cust. Status' ? $clink : '' }
+ FS::UI::Web::cust_header()
+ ),
+ ],
+ #'align' => 'rlrrrc'.FS::UI::Web::cust_aligns(),
+ 'align' => 'lr'.
+ ( $unearned ? 'rc' : '' ).
+ 'r'.
+ ( $unearned ? 'cc' : '' ).
+ 'rc'.
+ FS::UI::Web::cust_aligns(),
+ 'color' => [
+ #'',
+ '',
+ '',
+ ( $unearned ? ( '', '' ) : () ),
+ '',
+ ( $unearned ? ( '', '' ) : () ),
+ '',
+ '',
+ FS::UI::Web::cust_colors(),
+ ],
+ 'style' => [
+ #'',
+ '',
+ '',
+ ( $unearned ? ( '', '' ) : () ),
+ '',
+ ( $unearned ? ( '', '' ) : () ),
+ '',
+ '',
+ FS::UI::Web::cust_styles(),
+ ],
+&>
+<%init>
+
+#LOTS of false laziness below w/cust_credit_bill_pkg.cgi
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Financial reports');
+
+my $conf = new FS::Conf;
+
+my $unearned = '';
+
+#here is the agent virtualization
+my $agentnums_sql =
+ $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' );
+
+my @where = ( $agentnums_sql );