[freeside-commits] freeside/FS/FS/Report Table.pm,1.3,1.4
Mark Wells
mark at wavetail.420.am
Sat Jan 7 15:04:05 PST 2012
- Previous message: [freeside-commits] freeside/FS/FS/detail_format accountcode_default.pm, 1.1, 1.2 basic.pm, 1.1, 1.2 default.pm, 1.1, 1.2 description_default.pm, 1.1, 1.2 simple2.pm, 1.1, 1.2 simple.pm, 1.1, 1.2 source_default.pm, 1.1, 1.2 sum_count.pm, 1.2, 1.3 sum_duration.pm, 1.2, 1.3 sum_duration_prefix.pm, 1.2, 1.3
- Next message: [freeside-commits] freeside/FS/FS/Report/Table Monthly.pm, 1.25, 1.26
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /home/cvs/cvsroot/freeside/FS/FS/Report
In directory wavetail.420.am:/tmp/cvs-serv4642/FS/FS/Report
Modified Files:
Table.pm
Log Message:
projected sales report, #15393
Index: Table.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Report/Table.pm,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -w -d -r1.3 -r1.4
--- Table.pm 26 Dec 2011 20:24:16 -0000 1.3
+++ Table.pm 7 Jan 2012 23:04:02 -0000 1.4
@@ -4,7 +4,7 @@
use vars qw( @ISA $DEBUG );
use FS::Report;
use Time::Local qw( timelocal );
-use FS::UID qw( dbh );
+use FS::UID qw( dbh driver_name );
use FS::Report::Table;
use FS::CurrentUser;
@@ -347,6 +347,8 @@
interval and return that fraction of the recurring charges. This is
somewhat experimental.
+'project': enable if this is a projected period. This is very experimental.
+
=cut
sub cust_bill_pkg {
@@ -362,8 +364,7 @@
$sum;
}
-my $cust_bill_pkg_from =
- ' cust_bill_pkg
+my $cust_bill_pkg_join = '
LEFT JOIN cust_bill USING ( invnum )
LEFT JOIN cust_main USING ( custnum )
LEFT JOIN cust_pkg USING ( pkgnum )
@@ -373,6 +374,10 @@
sub cust_bill_pkg_setup {
my $self = shift;
my ($speriod, $eperiod, $agentnum, %opt) = @_;
+ # no projecting setup fees--use real invoices only
+ # but evaluate this anyway, because the design of projection is that
+ # if there are somehow real setup fees in the future, we want to count
+ # them
$agentnum ||= $opt{'agentnum'};
@@ -383,7 +388,8 @@
);
my $total_sql = "SELECT COALESCE(SUM(cust_bill_pkg.setup),0)
- FROM $cust_bill_pkg_from
+ FROM cust_bill_pkg
+ $cust_bill_pkg_join
WHERE " . join(' AND ', grep $_, @where);
$self->scalar_sql($total_sql);
@@ -394,6 +400,7 @@
my ($speriod, $eperiod, $agentnum, %opt) = @_;
$agentnum ||= $opt{'agentnum'};
+ my $cust_bill_pkg = $opt{'project'} ? 'v_cust_bill_pkg' : 'cust_bill_pkg';
my @where = (
'pkgnum != 0',
@@ -401,31 +408,40 @@
);
# subtract all usage from the line item regardless of date
- my $item_usage = '( SELECT COALESCE(SUM(cust_bill_pkg_detail.amount),0)
+ my $item_usage;
+ if ( $opt{'project'} ) {
+ $item_usage = 'usage'; #already calculated
+ }
+ else {
+ $item_usage = '( SELECT COALESCE(SUM(amount),0)
FROM cust_bill_pkg_detail
WHERE cust_bill_pkg_detail.billpkgnum = cust_bill_pkg.billpkgnum )';
+ }
my $recur_fraction = '';
if ( $opt{'distribute'} ) {
push @where, "cust_main.agentnum = $agentnum" if $agentnum;
push @where,
- "cust_bill_pkg.sdate < $eperiod",
- "cust_bill_pkg.edate > $speriod",
+ "$cust_bill_pkg.sdate < $eperiod",
+ "$cust_bill_pkg.edate > $speriod",
;
# the fraction of edate - sdate that's within [speriod, eperiod]
$recur_fraction = " *
- CAST(LEAST($eperiod, cust_bill_pkg.edate) -
- GREATEST($speriod, cust_bill_pkg.sdate) AS DECIMAL) /
- (cust_bill_pkg.edate - cust_bill_pkg.sdate)";
+ CAST(LEAST($eperiod, $cust_bill_pkg.edate) -
+ GREATEST($speriod, $cust_bill_pkg.sdate) AS DECIMAL) /
+ ($cust_bill_pkg.edate - $cust_bill_pkg.sdate)";
}
else {
+ # we don't want to have to create v_cust_bill
+ my $_date = $opt{'project'} ? 'v_cust_bill_pkg._date' : 'cust_bill._date';
push @where,
- $self->in_time_period_and_agent($speriod, $eperiod, $agentnum);
+ $self->in_time_period_and_agent($speriod, $eperiod, $agentnum, $_date);
}
- my $total_sql = "SELECT COALESCE(SUM(
- (cust_bill_pkg.recur - $item_usage) $recur_fraction),0)
- FROM $cust_bill_pkg_from
+ my $total_sql = 'SELECT '.
+ "COALESCE(SUM(($cust_bill_pkg.recur - $item_usage) $recur_fraction),0)
+ FROM $cust_bill_pkg
+ $cust_bill_pkg_join
WHERE ".join(' AND ', grep $_, @where);
$self->scalar_sql($total_sql);
@@ -627,6 +643,101 @@
=back
+=head1 METHODS
+
+=over 4
+
+=item init_projection
+
+Sets up for future projection of all observables on the report. Currently
+this is limited to 'cust_bill_pkg'.
+
+=cut
+
+sub init_projection {
+ # this is weird special case stuff--some redesign may be needed
+ # to use it for anything else
+ my $self = shift;
+
+ if ( driver_name ne 'Pg' ) {
+ # also database-specific for now
+ die "projection reports not supported on this platform";
+ }
+
+ my %items = map {$_ => 1} @{ $self->{items} };
+ if ($items{'cust_bill_pkg'}) {
+ my $dbh = dbh;
+ # v_ for 'virtual'
+ my @sql = (
+ # could use TEMPORARY TABLE but we're already transaction-protected
+ 'DROP TABLE IF EXISTS v_cust_bill_pkg',
+ 'CREATE TABLE v_cust_bill_pkg ' .
+ '(LIKE cust_bill_pkg,
+ usage numeric(10,2), _date integer, expire integer)',
+ # XXX this should be smart enough to take only the ones with
+ # sdate/edate overlapping the ROI, for performance
+ "INSERT INTO v_cust_bill_pkg (
+ SELECT cust_bill_pkg.*,
+ (SELECT COALESCE(SUM(amount),0) FROM cust_bill_pkg_detail
+ WHERE cust_bill_pkg_detail.billpkgnum = cust_bill_pkg.billpkgnum),
+ cust_bill._date,
+ cust_pkg.expire
+ FROM cust_bill_pkg $cust_bill_pkg_join
+ )",
+ );
+ foreach my $sql (@sql) {
+ warn "[init_projection] $sql\n" if $DEBUG;
+ $dbh->do($sql) or die $dbh->errstr;
+ }
+ }
+}
+
+=item extend_projection START END
+
+Generates data for the next period of projection. This will be called
+for sequential periods where the END of one equals the START of the next
+(with no gaps).
+
+=cut
+
+sub extend_projection {
+ my $self = shift;
+ my ($speriod, $eperiod) = @_;
+ my %items = map {$_ => 1} @{ $self->{items} };
+ if ($items{'cust_bill_pkg'}) {
+ # append, head-to-tail, new line items identical to any that end within the
+ # period (and aren't expiring)
+ my @fields = ( FS::cust_bill_pkg->fields, qw( usage _date expire ) );
+ my $insert_fields = join(',', @fields);
+ #advance (sdate, edate) by one billing period
+ foreach (@fields) {
+ if ($_ eq 'edate') {
+ $_ = '(edate + (edate - sdate)) AS edate' #careful of integer overflow
+ }
+ elsif ($_ eq 'sdate') {
+ $_ = 'edate AS sdate'
+ }
+ elsif ($_ eq 'setup') {
+ $_ = '0 AS setup' #because recurring only
+ }
+ elsif ($_ eq '_date') {
+ $_ = '(_date + (edate - sdate)) AS _date'
+ }
+ }
+ my $select_fields = join(',', @fields);
+ my $dbh = dbh;
+ my $sql =
+ "INSERT INTO v_cust_bill_pkg ($insert_fields)
+ SELECT $select_fields FROM v_cust_bill_pkg
+ WHERE edate >= $speriod AND edate < $eperiod
+ AND recur > 0
+ AND (expire IS NULL OR expire > edate)";
+ warn "[extend_projection] $sql\n" if $DEBUG;
+ my $rows = $dbh->do($sql) or die $dbh->errstr;
+ warn "[extend_projection] $rows rows\n" if $DEBUG;
+ }
+}
+
=head1 BUGS
Documentation.
- Previous message: [freeside-commits] freeside/FS/FS/detail_format accountcode_default.pm, 1.1, 1.2 basic.pm, 1.1, 1.2 default.pm, 1.1, 1.2 description_default.pm, 1.1, 1.2 simple2.pm, 1.1, 1.2 simple.pm, 1.1, 1.2 source_default.pm, 1.1, 1.2 sum_count.pm, 1.2, 1.3 sum_duration.pm, 1.2, 1.3 sum_duration_prefix.pm, 1.2, 1.3
- Next message: [freeside-commits] freeside/FS/FS/Report/Table Monthly.pm, 1.25, 1.26
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the freeside-commits
mailing list