summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorivan <ivan>2010-02-06 02:57:12 +0000
committerivan <ivan>2010-02-06 02:57:12 +0000
commit942c8b05b17b119a3dad84d7035c76b481dc5b99 (patch)
treeafa91e2825c0c289bfab329a36c274b393c91248
parent50aae8bb98effd9b9cc4736aa6d3333245d349d8 (diff)
discount reporting, RT#6679
-rw-r--r--FS/FS.pm2
-rw-r--r--FS/FS/Mason.pm2
-rw-r--r--FS/FS/Report/Table/Monthly.pm47
-rw-r--r--FS/FS/Schema.pm14
-rw-r--r--FS/FS/cust_bill_pkg.pm15
-rw-r--r--FS/FS/cust_bill_pkg_discount.pm158
-rw-r--r--FS/FS/cust_main.pm4
-rw-r--r--FS/FS/cust_pkg.pm5
-rw-r--r--FS/FS/cust_pkg_discount.pm21
-rw-r--r--FS/FS/part_pkg/flat.pm11
-rw-r--r--FS/MANIFEST2
-rw-r--r--FS/t/cust_bill_pkg_discount.t5
-rw-r--r--httemplate/elements/menu.html9
-rw-r--r--httemplate/misc/delete-cust_pkg_discount.html4
-rw-r--r--httemplate/search/cust_bill_pkg_discount.html151
-rw-r--r--httemplate/search/cust_pkg_discount.html122
-rw-r--r--httemplate/search/report_cust_bill_pkg_discount.html47
-rw-r--r--httemplate/search/report_cust_pkg_discount.html50
18 files changed, 660 insertions, 9 deletions
diff --git a/FS/FS.pm b/FS/FS.pm
index bfa23af..67c2cd2 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -228,6 +228,8 @@ L<FS::cust_pkg_detail> - Customer package details class
L<FS:;cust_pkg_discount> - Customer package discount class
+L<FS:;cust_bill_pkg_discount> - Customer package discount line item application class
+
L<FS:;discount> - Discount class
L<FS::reason_type> - Reason type class
diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm
index d812e81..f20ea64 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 fa9949d..9e7a288 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 ad094d7..19c2e8e 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 cd049d1..cb070d7 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 0000000..e7dd5f2
--- /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<FS::cust_bill_pkg>)
+
+=item pkgdiscountnum
+
+Customer discount (see L<FS::cust_pkg_discount>)
+
+=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<hash> 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<FS::cust_bill_pkg>).
+
+=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<FS::cust_pkg_discount>).
+
+=cut
+
+sub cust_pkg_discount {
+ my $self = shift;
+ qsearchs( 'cust_pkg_discount', { 'pkgdiscountnum' => $self->pkgdiscountnum });
+}
+
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 590e32f..d4ce0fd 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 acc73df..c3734b5 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 8dd00de..1b97bba 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 e5fc089..b825dde 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 a92b9dd..7152345 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 0000000..74923e1
--- /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 5090abc..1694a59 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 69168af..0bdaa13 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;
</%init>
diff --git a/httemplate/search/cust_bill_pkg_discount.html b/httemplate/search/cust_bill_pkg_discount.html
new file mode 100644
index 0000000..088b291
--- /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') || '$';
+
+</%init>
diff --git a/httemplate/search/cust_pkg_discount.html b/httemplate/search/cust_pkg_discount.html
new file mode 100644
index 0000000..233345e
--- /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;
+
+</%init>
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 0000000..f1879d4
--- /dev/null
+++ b/httemplate/search/report_cust_bill_pkg_discount.html
@@ -0,0 +1,47 @@
+<% include('/elements/header.html', 'Discount report' ) %>
+
+<FORM ACTION="cust_bill_pkg_discount.html" METHOD="GET">
+
+
+<TABLE>
+
+ <% 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',
+ )
+ %>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% 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};
+
+</%init>
diff --git a/httemplate/search/report_cust_pkg_discount.html b/httemplate/search/report_cust_pkg_discount.html
new file mode 100644
index 0000000..7ebd44f
--- /dev/null
+++ b/httemplate/search/report_cust_pkg_discount.html
@@ -0,0 +1,50 @@
+<% include('/elements/header.html', 'Package discount report' ) %>
+
+<FORM ACTION="cust_pkg_discount.html" METHOD="GET">
+
+
+<TABLE>
+
+ <TR>
+ <TD>Discount status</TD>
+ <TD>
+ <SELECT NAME="status">
+ <OPTION VALUE="active">Active
+ <OPTION VALUE="expired">Expired
+ <OPTION VALUE="">(all)
+ </SELECT>
+ </TD>
+ </TR>
+
+ <% 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,
+ )
+ %>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<% 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};
+
+</%init>