From 942c8b05b17b119a3dad84d7035c76b481dc5b99 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 6 Feb 2010 02:57:12 +0000 Subject: [PATCH] discount reporting, RT#6679 --- FS/FS.pm | 2 + FS/FS/Mason.pm | 2 + FS/FS/Report/Table/Monthly.pm | 47 ++++++ FS/FS/Schema.pm | 14 ++ FS/FS/cust_bill_pkg.pm | 15 +- FS/FS/cust_bill_pkg_discount.pm | 158 +++++++++++++++++++++ FS/FS/cust_main.pm | 4 +- FS/FS/cust_pkg.pm | 5 +- FS/FS/cust_pkg_discount.pm | 21 ++- FS/FS/part_pkg/flat.pm | 11 ++ FS/MANIFEST | 2 + FS/t/cust_bill_pkg_discount.t | 5 + httemplate/elements/menu.html | 9 ++ httemplate/misc/delete-cust_pkg_discount.html | 4 +- httemplate/search/cust_bill_pkg_discount.html | 151 ++++++++++++++++++++ httemplate/search/cust_pkg_discount.html | 122 ++++++++++++++++ .../search/report_cust_bill_pkg_discount.html | 47 ++++++ httemplate/search/report_cust_pkg_discount.html | 50 +++++++ 18 files changed, 660 insertions(+), 9 deletions(-) create mode 100644 FS/FS/cust_bill_pkg_discount.pm create mode 100644 FS/t/cust_bill_pkg_discount.t create mode 100644 httemplate/search/cust_bill_pkg_discount.html create mode 100644 httemplate/search/cust_pkg_discount.html create mode 100644 httemplate/search/report_cust_bill_pkg_discount.html create mode 100644 httemplate/search/report_cust_pkg_discount.html diff --git a/FS/FS.pm b/FS/FS.pm index bfa23af79..67c2cd26f 100644 --- a/FS/FS.pm +++ b/FS/FS.pm @@ -228,6 +228,8 @@ L - Customer package details class L - Customer package discount class +L - Customer package discount line item application class + L - Discount class L - Reason type class diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index d812e8184..f20ea647a 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -228,6 +228,8 @@ if ( -e $addl_handler_use_file ) { use FS::contact; use FS::svc_pbx; use FS::discount; + use FS::cust_pkg_discount; + use FS::cust_bill_pkg_discount; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Report/Table/Monthly.pm b/FS/FS/Report/Table/Monthly.pm index fa9949d49..9e7a2882f 100644 --- a/FS/FS/Report/Table/Monthly.pm +++ b/FS/FS/Report/Table/Monthly.pm @@ -417,6 +417,53 @@ sub cust_bill_pkg_detail { } +sub cust_bill_pkg_discount { + my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_; + + #my $where = ''; + #my $comparison = ''; + #if ( $opt{'classnum'} =~ /^(\d+)$/ ) { + # if ( $1 == 0 ) { + # $comparison = "IS NULL"; + # } else { + # $comparison = "= $1"; + # } + # + # if ( $opt{'use_override'} ) { + # $where = "( + # part_pkg.classnum $comparison AND pkgpart_override IS NULL OR + # override.classnum $comparison AND pkgpart_override IS NOT NULL + # )"; + # } else { + # $where = "part_pkg.classnum $comparison"; + # } + #} + + $agentnum ||= $opt{'agentnum'}; + + my $total_sql = + " SELECT COALESCE( SUM( cust_bill_pkg_discount.amount ), 0 ) "; + + #$total_sql .= + # " / CASE COUNT(cust_pkg.*) WHEN 0 THEN 1 ELSE COUNT(cust_pkg.*) END " + # if $opt{average_per_cust_pkg}; + + $total_sql .= + " FROM cust_bill_pkg_discount + LEFT JOIN cust_bill_pkg USING ( billpkgnum ) + LEFT JOIN cust_bill USING ( invnum ) + LEFT JOIN cust_main USING ( custnum ) + WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum); + # LEFT JOIN cust_pkg_discount USING ( pkgdiscountnum ) + # LEFT JOIN discount USING ( discountnum ) + # LEFT JOIN cust_pkg USING ( pkgnum ) + # LEFT JOIN part_pkg USING ( pkgpart ) + # LEFT JOIN part_pkg AS override ON pkgpart_override = override.pkgpart + + return $self->scalar_sql($total_sql); + +} + sub setup_pkg { shift->pkg_field( @_, 'setup' ); } sub susp_pkg { shift->pkg_field( @_, 'susp' ); } sub cancel_pkg { shift->pkg_field( @_, 'cancel'); } diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index ad094d7c1..19c2e8e58 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1317,12 +1317,26 @@ sub tables_hashref { 'months_used', 'decimal', 'NULL', '', '', '', 'end_date', @date_type, '', '', 'otaker', 'varchar', '', 32, '', '', + 'disabled', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'pkgdiscountnum', 'unique' => [], 'index' => [ [ 'pkgnum' ], [ 'discountnum' ] ], }, + 'cust_bill_pkg_discount' => { + 'columns' => [ + 'billpkgdiscountnum', 'serial', '', '', '', '', + 'billpkgnum', 'int', '', '', '', '', + 'pkgdiscountnum', 'int', '', '', '', '', + 'amount', @money_type, '', '', + 'months', 'decimal', 'NULL', '', '', '', + ], + 'primary_key' => 'billpkgdiscountnum', + 'unique' => [], + 'index' => [ [ 'billpkgnum' ], [ 'pkgdiscountnum' ] ], + }, + 'discount' => { 'columns' => [ 'discountnum', 'serial', '', '', '', '', diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index cd049d121..cb070d77a 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -174,6 +174,17 @@ sub insert { } } + if ( $self->get('discounts') ) { + foreach my $cust_bill_pkg_discount ( @{$self->get('discounts')} ) { + $cust_bill_pkg_discount->billpkgnum($self->billpkgnum); + $error = $cust_bill_pkg_discount->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error inserting cust_bill_pkg_discount: $error"; + } + } + } + if ( $self->_cust_tax_exempt_pkg ) { foreach my $cust_tax_exempt_pkg ( @{$self->_cust_tax_exempt_pkg} ) { $cust_tax_exempt_pkg->billpkgnum($self->billpkgnum); @@ -763,10 +774,10 @@ sub cust_bill_pkg_display { my $type = $opt{type} if exists $opt{type}; my @result; - if ( scalar( $self->get('display') ) ) { + if ( $self->get('display') ) { @result = grep { defined($type) ? ($type eq $_->type) : 1 } @{ $self->get('display') }; - }else{ + } else { my $hashref = { 'billpkgnum' => $self->billpkgnum }; $hashref->{type} = $type if defined($type); diff --git a/FS/FS/cust_bill_pkg_discount.pm b/FS/FS/cust_bill_pkg_discount.pm new file mode 100644 index 000000000..e7dd5f22f --- /dev/null +++ b/FS/FS/cust_bill_pkg_discount.pm @@ -0,0 +1,158 @@ +package FS::cust_bill_pkg_discount; + +use strict; +use base qw( FS::cust_main_Mixin FS::Record ); +use FS::Record qw( qsearch qsearchs ); +use FS::cust_bill_pkg; +use FS::cust_pkg_discount; + +=head1 NAME + +FS::cust_bill_pkg_discount - Object methods for cust_bill_pkg_discount records + +=head1 SYNOPSIS + + use FS::cust_bill_pkg_discount; + + $record = new FS::cust_bill_pkg_discount \%hash; + $record = new FS::cust_bill_pkg_discount { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_bill_pkg_discount object represents the slice of a customer +applied to a line item. FS::cust_bill_pkg_discount inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item billpkgdiscountnum + +primary key + +=item billpkgnum + +Line item (see L) + +=item pkgdiscountnum + +Customer discount (see L) + +=item amount + +Amount discounted from the line itme. + +=item months + +Number of months of discount this represents. + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new record. To add the record 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 method. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'cust_bill_pkg_discount'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +# the insert method can be inherited from FS::Record + +=item delete + +Delete this record from the database. + +=cut + +# the delete method can be inherited from FS::Record + +=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 + +# the replace method can be inherited from FS::Record + +=item check + +Checks all fields to make sure this is a valid record. 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 $error = + $self->ut_numbern('billpkgdiscountnum') + || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum' ) + || $self->ut_foreign_key('pkgdiscountnum', 'cust_pkg_discount', 'pkgdiscountnum' ) + || $self->ut_money('amount') + || $self->ut_float('months') + ; + return $error if $error; + + $self->SUPER::check; +} + +=item cust_bill_pkg + +Returns the associated line item (see L). + +=cut + +sub cust_bill_pkg { + my $self = shift; + qsearchs( 'cust_bill_pkg', { 'billpkgnum' => $self->billpkgnum } ) ; +} + +=item cust_pkg_discount + +Returns the associated customer discount (see L). + +=cut + +sub cust_pkg_discount { + my $self = shift; + qsearchs( 'cust_pkg_discount', { 'pkgdiscountnum' => $self->pkgdiscountnum }); +} + + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 590e32ff2..d4ce0fd67 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3065,7 +3065,7 @@ sub _make_lines { my $old_cust_pkg = new FS::cust_pkg \%hash; my @details = (); - + my @discounts = (); my $lineitems = 0; $cust_pkg->pkgpart($part_pkg->pkgpart); @@ -3150,6 +3150,7 @@ sub _make_lines { ); my %param = ( 'precommit_hooks' => $precommit_hooks, 'increment_next_bill' => $increment_next_bill, + 'discounts' => \@discounts, ); my $method = $options{cancel} ? 'calc_cancel' : 'calc_recur'; @@ -3229,6 +3230,7 @@ sub _make_lines { 'unitrecur' => $unitrecur, 'quantity' => $cust_pkg->quantity, 'details' => \@details, + 'discounts' => \@discounts, 'hidden' => $part_pkg->hidden, }; diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index acc73dfda..c3734b54e 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -2388,10 +2388,7 @@ sub cust_pkg_discount { sub cust_pkg_discount_active { my $self = shift; - grep { my $d = $_->discount; - ! $d->months || $_->months_used < $d->months; # XXX also end date - } - $self->cust_pkg_discount; + grep { $_->status eq 'active' } $self->cust_pkg_discount; } =back diff --git a/FS/FS/cust_pkg_discount.pm b/FS/FS/cust_pkg_discount.pm index 8dd00de89..1b97bba03 100644 --- a/FS/FS/cust_pkg_discount.pm +++ b/FS/FS/cust_pkg_discount.pm @@ -1,7 +1,7 @@ package FS::cust_pkg_discount; use strict; -use base qw( FS::Record ); +use base qw( FS::cust_main_Mixin FS::Record ); use FS::Record qw( dbh qsearchs ); # qsearch ); use FS::cust_pkg; use FS::discount; @@ -165,6 +165,7 @@ sub check { || $self->ut_float('months_used') #actually decimal, but this will do || $self->ut_numbern('end_date') || $self->ut_text('otaker') + || $self->ut_enum('disabled', [ '', 'Y' ] ) ; return $error if $error; @@ -207,6 +208,24 @@ sub increment_months_used { $self->replace(); } +=item status + +=cut + +sub status { + my $self = shift; + my $discount = $self->discount; + + if ( $self->disabled ne 'Y' + and ( ! $discount->months || $self->months_used < $discount->months ) + #XXX also end date + ) { + 'active'; + } else { + 'expired'; + } +} + =back =head1 BUGS diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm index e5fc089c4..b825dded6 100644 --- a/FS/FS/part_pkg/flat.pm +++ b/FS/FS/part_pkg/flat.pm @@ -11,6 +11,7 @@ use List::Util qw(min); # max); use FS::UI::bytecount; use FS::Conf; use FS::part_pkg; +use FS::cust_bill_pkg_discount; @ISA = qw(FS::part_pkg); @@ -190,6 +191,16 @@ sub calc_discount { $amount *= $months; $amount = sprintf('%.2f', $amount); + next unless $amount > 0; + + #record details in cust_bill_pkg_discount + my $cust_bill_pkg_discount = new FS::cust_bill_pkg_discount { + 'pkgdiscountnum' => $cust_pkg_discount->pkgdiscountnum, + 'amount' => $amount, + 'months' => $months, + }; + push @{ $param->{'discounts'} }, $cust_bill_pkg_discount; + #add details on discount to invoice my $conf = new FS::Conf; my $money_char = $conf->config('money_char') || '$'; diff --git a/FS/MANIFEST b/FS/MANIFEST index a92b9ddd7..71523458a 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -480,3 +480,5 @@ FS/discount.pm t/discount.t FS/cust_pkg_discount.pm t/cust_pkg_discount.t +FS/cust_bill_pkg_discount.pm +t/cust_bill_pkg_discount.t diff --git a/FS/t/cust_bill_pkg_discount.t b/FS/t/cust_bill_pkg_discount.t new file mode 100644 index 000000000..74923e1b0 --- /dev/null +++ b/FS/t/cust_bill_pkg_discount.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::cust_bill_pkg_discount; +$loaded=1; +print "ok 1\n"; diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 5090abc73..1694a5927 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -102,6 +102,13 @@ tie my %report_invoices, 'Tie::IxHash', 'Advanced invoice reports' => [ $fsurl.'search/report_cust_bill.html', 'by agent, date range, etc.' ], ; +tie my %report_discounts, 'Tie::IxHash', + 'Discount graph' => [ $fsurl. 'graph/report_cust_bill_pkg_discount.html', 'Discount overview per month' ], + 'Discount detail' => [ $fsurl.'search/report_cust_bill_pkg_discount.html', 'Discount report (by employee and/or date range)' ], + #awful name + 'Package discounts' => [ $fsurl.'search/report_cust_pkg_discount.html', 'Active/inactive discounts by package' ], +; + tie my %report_services, 'Tie::IxHash'; if ( $curuser->access_right('Configuration') ) { $report_services{'Service definitions'} = [ $fsurl.'browse/part_svc.cgi?orderby=active', 'Service definitions by number of active packages' ]; @@ -262,6 +269,8 @@ $report_menu{'Customers'} = [ \%report_customers, 'Customer reports' ] if $curuser->access_right('List customers'); $report_menu{'Invoices'} = [ \%report_invoices, 'Invoice reports' ] if $curuser->access_right('List invoices'); +$report_menu{'Discounts'} = [ \%report_discounts, 'Discount reports' ] + if $curuser->access_right('Financial reports'); $report_menu{'Payments'} = [ \%report_payments, 'Payment reports' ] if $curuser->access_right('Financial reports'); $report_menu{'Packages'} = [ \%report_packages, 'Package reports' ] diff --git a/httemplate/misc/delete-cust_pkg_discount.html b/httemplate/misc/delete-cust_pkg_discount.html index 69168af3b..0bdaa13b3 100644 --- a/httemplate/misc/delete-cust_pkg_discount.html +++ b/httemplate/misc/delete-cust_pkg_discount.html @@ -25,6 +25,8 @@ my $cust_pkg_discount = my $cust_pkg = $cust_pkg_discount->cust_pkg; my $custnum = $cust_pkg->custnum; -my $error = $cust_pkg_discount->delete; +$cust_pkg_discount->disabled('Y'); + +my $error = $cust_pkg_discount->replace; diff --git a/httemplate/search/cust_bill_pkg_discount.html b/httemplate/search/cust_bill_pkg_discount.html new file mode 100644 index 000000000..088b29115 --- /dev/null +++ b/httemplate/search/cust_bill_pkg_discount.html @@ -0,0 +1,151 @@ +<% include( 'elements/search.html', + 'title' => 'Discounts', + 'name' => 'discounts', + 'query' => $query, + 'count_query' => $count_query, + 'count_addl' => [ $money_char. '%.2f total', ], + 'header' => [ + #'#', + 'Discount', + 'Amount', + 'Months', + 'Package', + 'Invoice', + 'Date', + FS::UI::Web::cust_header(), + ], + 'fields' => [ + #'billpkgdiscountnum', + sub { $_[0]->cust_pkg_discount->discount->description }, + sub { sprintf($money_char.'%.2f', shift->amount ) }, + sub { my $m = shift->months; + $m =~ /\./ ? sprintf('%.2f', $m) : $m; + }, + 'pkg',#sub { $_[0]->cust_bill_pkg->cust_pkg->part_pkg->pkg }, + 'invnum', + sub { time2str('%b %d %Y', shift->_date ) }, + \&FS::UI::Web::cust_fields, + ], + 'links' => [ + #'', + '', #link to customer discount??? + '', + '', + '', + $ilink, + $ilink, + ( map { $_ ne 'Cust. Status' ? $clink : '' } + FS::UI::Web::cust_header() + ), + ], + #'align' => 'rlrrrc'.FS::UI::Web::cust_aligns(), + 'align' => 'lrrlrr'.FS::UI::Web::cust_aligns(), + 'color' => [ + #'', + '', + '', + '', + '', + '', + '', + FS::UI::Web::cust_colors(), + ], + 'style' => [ + #'', + '', + '', + '', + '', + '', + '', + FS::UI::Web::cust_styles(), + ], + ) +%> +<%init> + +#a little false laziness below w/cust_bill_pkg.cgi + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +my $conf = new FS::Conf; + +#here is the agent virtualization +my $agentnums_sql = + $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' ); + +my @where = ( $agentnums_sql ); + +my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); +push @where, "_date >= $beginning", + "_date <= $ending"; + +if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + push @where, "cust_main.agentnum = $1"; +} + +# #classnum +# # not specified: all classes +# # 0: empty class +# # N: classnum +# my $use_override = $cgi->param('use_override'); +# if ( $cgi->param('classnum') =~ /^(\d+)$/ ) { +# my $comparison = ''; +# if ( $1 == 0 ) { +# $comparison = "IS NULL"; +# } else { +# $comparison = "= $1"; +# } +# +# if ( $use_override ) { +# push @where, "( +# part_pkg.classnum $comparison AND pkgpart_override IS NULL OR +# override.classnum $comparison AND pkgpart_override IS NOT NULL +# )"; +# } else { +# push @where, "part_pkg.classnum $comparison"; +# } +# } + +my $count_query = "SELECT COUNT(*), SUM(amount)"; + +my $join_cust = ' JOIN cust_bill_pkg USING ( billpkgnum ) + JOIN cust_bill USING ( invnum ) + LEFT JOIN cust_main USING ( custnum ) '; + +my $join_pkg = ' LEFT JOIN cust_pkg USING ( pkgnum ) + LEFT JOIN part_pkg USING ( pkgpart ) '; + #LEFT JOIN part_pkg AS override + # ON pkgpart_override = override.pkgpart '; + +my $where = ' WHERE '. join(' AND ', @where); + +$count_query .= " FROM cust_bill_pkg_discount $join_cust $join_pkg $where"; + +my @select = ( + 'cust_bill_pkg_discount.*', + #'cust_bill_pkg.*', + 'cust_bill.invnum', + 'cust_bill._date', + ); +push @select, 'part_pkg.pkg'; +push @select, 'cust_main.custnum', + FS::UI::Web::cust_sql_fields(); + +my $query = { + 'table' => 'cust_bill_pkg_discount', + 'addl_from' => "$join_cust $join_pkg", + 'hashref' => {}, + 'select' => join(', ', @select ), + 'extra_sql' => $where, + 'order_by' => 'ORDER BY _date, billpkgdiscountnum', +}; + +my $ilink = [ "${p}view/cust_bill.cgi?", 'invnum' ]; +my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ]; + +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + + diff --git a/httemplate/search/cust_pkg_discount.html b/httemplate/search/cust_pkg_discount.html new file mode 100644 index 000000000..233345e1c --- /dev/null +++ b/httemplate/search/cust_pkg_discount.html @@ -0,0 +1,122 @@ +<% include( 'elements/search.html', + 'title' => 'Package discounts', + 'name' => 'discounts', + 'query' => $query, + 'count_query' => $count_query, + #'redirect' => $link, + 'header' => [ 'Status', + 'Discount', + 'Months used', + 'Employee', + 'Package', + FS::UI::Web::cust_header( + # $cgi->param('cust_fields') + ), + ], + 'fields' => [ + sub { ucfirst( shift->status ) }, + sub { shift->discount->description }, + sub { my $m = shift->months_used; + $m =~ /\./ ? sprintf('%.2f',$m) : $m; + }, + 'otaker', + 'pkg', + \&FS::UI::Web::cust_fields, + ], + 'links' => [ + '', + '', + '', + '', + '', + ( map { $_ ne 'Cust. Status' ? $clink : ''} + FS::UI::Web::cust_header() + ), + ], + 'align' => 'clrll'. FS::UI::Web::cust_aligns(), + 'color' => [ + '', + '', + '', + '', + '', + FS::UI::Web::cust_colors(), + ], + 'style' => [ + '', + '', + '', + '', + '', + FS::UI::Web::cust_styles(), + ], + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +#my $conf = new FS::Conf; + +#here is the agent virtualization +my $agentnums_sql = + $FS::CurrentUser::CurrentUser->agentnums_sql( 'table' => 'cust_main' ); + +my @where = ( $agentnums_sql ); + +#status +if ( $cgi->param('status') eq 'active' ) { + push @where, " ( cust_pkg_discount.disabled IS NULL + OR cust_pkg_discount.disabled != 'Y' ) + AND ( months IS NULL OR months_used < months ) "; + #XXX also end date +} elsif ( $cgi->param('status') eq 'expired' ) { + push @where, " ( cust_pkg_discount.disabled IS NOT NULL + AND cust_pkg_discount.disabled = 'Y' ) + OR ( months IS NOT NULL AND months_used >= months ) + "; #XXX also end date +} + +#otaker +if ( $cgi->param('otaker') && $cgi->param('otaker') =~ /^([\w\.\-]+)$/ ) { + push @where, "cust_pkg_discount.otaker = '$1'"; +} + +#agent +if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) { + push @where, "cust_main.agentnum = $1"; +} + +my $count_query = "SELECT COUNT(*), SUM(amount)"; + +my $join = ' LEFT JOIN discount USING ( discountnum ) + LEFT JOIN cust_pkg USING ( pkgnum ) + LEFT JOIN part_pkg USING ( pkgpart ) + LEFT JOIN cust_main USING ( custnum ) '; + +my $where = ' WHERE '. join(' AND ', @where); + +$count_query .= " FROM cust_pkg_discount $join $where"; + +my @select = ( + 'cust_pkg_discount.*', + 'part_pkg.pkg', + ); +push @select, 'cust_main.custnum', + FS::UI::Web::cust_sql_fields(); + +my $query = { + 'table' => 'cust_pkg_discount', + 'addl_from' => $join, + 'hashref' => {}, + 'select' => join(', ', @select ), + 'extra_sql' => $where, + 'order_by' => 'ORDER BY pkgdiscountnum', +}; + +my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ]; + +my $conf = new FS::Conf; + + diff --git a/httemplate/search/report_cust_bill_pkg_discount.html b/httemplate/search/report_cust_bill_pkg_discount.html new file mode 100644 index 000000000..f1879d4a9 --- /dev/null +++ b/httemplate/search/report_cust_bill_pkg_discount.html @@ -0,0 +1,47 @@ +<% include('/elements/header.html', 'Discount report' ) %> + +
+ + + + + <% include( '/elements/tr-select-otaker.html', + 'label' => 'Discounts by employee: ', + 'otakers' => \@otakers, + ) + %> + + <% include( '/elements/tr-select-agent.html', + 'curr_value' => scalar( $cgi->param('agentnum') ), + 'label' => 'for agent: ', + 'disable_empty' => 0, + ) + %> + + <% include( '/elements/tr-input-beginning_ending.html' ) %> + + <% include( '/elements/tr-input-lessthan_greaterthan.html', + 'label' => 'Amount', + 'field' => 'amount', + ) + %> + +
+ +
+ + +
+ +<% include('/elements/footer.html') %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_pkg_discount") + or die dbh->errstr; +$sth->execute or die $sth->errstr; +my @otakers = map { $_->[0] } @{$sth->fetchall_arrayref}; + + diff --git a/httemplate/search/report_cust_pkg_discount.html b/httemplate/search/report_cust_pkg_discount.html new file mode 100644 index 000000000..7ebd44f75 --- /dev/null +++ b/httemplate/search/report_cust_pkg_discount.html @@ -0,0 +1,50 @@ +<% include('/elements/header.html', 'Package discount report' ) %> + +
+ + + + + + + + + + <% include( '/elements/tr-select-otaker.html', + 'label' => 'Discounts by employee: ', + 'otakers' => \@otakers, + ) + %> + + <% include( '/elements/tr-select-agent.html', + 'curr_value' => scalar( $cgi->param('agentnum') ), + 'label' => 'for agent: ', + 'disable_empty' => 0, + ) + %> + +
Discount status + +
+ +
+ + +
+ +<% include('/elements/footer.html') %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Financial reports'); + +my $sth = dbh->prepare("SELECT DISTINCT otaker FROM cust_pkg_discount") + or die dbh->errstr; +$sth->execute or die $sth->errstr; +my @otakers = map { $_->[0] } @{$sth->fetchall_arrayref}; + + -- 2.11.0