push @where, "refnum = ".$opt{'refnum'};
}
+ push @where, $self->with_cust_classnum(%opt);
+
$self->scalar_sql(
"SELECT COUNT(*) FROM cust_main $join WHERE ".join(' AND ', @where)
);
sub invoiced { #invoiced
my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
+ my $sql = 'SELECT SUM(cust_bill.charged) FROM cust_bill';
+ if ( $opt{'setuprecur'} ) {
+ $sql = 'SELECT SUM('.
+ FS::cust_bill_pkg->charged_sql($speriod, $eperiod, %opt).
+ ') FROM cust_bill_pkg JOIN cust_bill USING (invnum)';
+ }
+
$self->scalar_sql("
- SELECT SUM(charged)
- FROM cust_bill
+ $sql
LEFT JOIN cust_main USING ( custnum )
- WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum)
- . (%opt ? $self->for_custnum(%opt) : '')
+ WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum).
+ $self->for_opts(%opt)
);
}
sub netsales { #net sales
my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
- $self->invoiced($speriod,$eperiod,$agentnum,%opt)
- - $self->netcredits($speriod,$eperiod,$agentnum,%opt);
+ $self->invoiced( $speriod, $eperiod, $agentnum, %opt)
+ - $self->netcredits($speriod, $eperiod, $agentnum, %opt);
}
=item cashflow: payments - refunds
=cut
sub netcashflow {
- my( $self, $speriod, $eperiod, $agentnum ) = @_;
+ my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
- $self->receipts($speriod, $eperiod, $agentnum)
- - $self->netrefunds( $speriod, $eperiod, $agentnum);
+ $self->receipts( $speriod, $eperiod, $agentnum, %opt)
+ - $self->netrefunds( $speriod, $eperiod, $agentnum, %opt);
}
=item payments: The sum of payments received in the period.
SELECT SUM(paid)
FROM cust_pay
LEFT JOIN cust_main USING ( custnum )
- WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum)
- . (%opt ? $self->for_custnum(%opt) : '')
+ WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum).
+ $self->for_opts(%opt)
);
}
=cut
sub credits {
- my( $self, $speriod, $eperiod, $agentnum ) = @_;
+ my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
$self->scalar_sql("
SELECT SUM(amount)
FROM cust_credit
LEFT JOIN cust_main USING ( custnum )
- WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum)
+ WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum).
+ $self->for_opts(%opt)
);
}
SELECT SUM(refund)
FROM cust_refund
LEFT JOIN cust_main USING ( custnum )
- WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum)
- . (%opt ? $self->for_custnum(%opt) : '')
+ WHERE ". $self->in_time_period_and_agent($speriod, $eperiod, $agentnum).
+ $self->for_opts(%opt)
);
}
sub netcredits {
my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
+
+ my $sql = 'SELECT SUM(cust_credit_bill.amount) FROM cust_credit_bill';
+ if ( $opt{'setuprecur'} ) {
+ $sql = 'SELECT SUM('.
+ FS::cust_bill_pkg->credited_sql($speriod, $eperiod, %opt).
+ ') FROM cust_bill_pkg';
+ }
+
$self->scalar_sql("
- SELECT SUM(cust_credit_bill.amount)
- FROM cust_credit_bill
+ $sql
LEFT JOIN cust_bill USING ( invnum )
LEFT JOIN cust_main USING ( custnum )
WHERE ". $self->in_time_period_and_agent( $speriod,
$eperiod,
$agentnum,
'cust_bill._date'
- )
- . (%opt ? $self->for_custnum(%opt) : '')
+ ).
+ $self->for_opts(%opt)
);
}
=cut
sub receipts { #net payments
- my( $self, $speriod, $eperiod, $agentnum ) = @_;
+ my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
+
+ my $sql = 'SELECT SUM(cust_bill_pay.amount) FROM cust_bill_pay';
+ if ( $opt{'setuprecur'} ) {
+ $sql = 'SELECT SUM('.
+ FS::cust_bill_pkg->paid_sql($speriod, $eperiod, %opt).
+ ') FROM cust_bill_pkg';
+ }
+
$self->scalar_sql("
- SELECT SUM(cust_bill_pay.amount)
- FROM cust_bill_pay
+ $sql
LEFT JOIN cust_bill USING ( invnum )
LEFT JOIN cust_main USING ( custnum )
WHERE ". $self->in_time_period_and_agent( $speriod,
$eperiod,
$agentnum,
'cust_bill._date'
- )
+ ).
+ $self->for_opts(%opt)
);
}
=cut
sub netrefunds {
- my( $self, $speriod, $eperiod, $agentnum ) = @_;
+ my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
$self->scalar_sql("
SELECT SUM(cust_credit_refund.amount)
FROM cust_credit_refund
$eperiod,
$agentnum,
'cust_credit._date'
- )
+ ).
+ $self->for_opts(%opt)
);
}
sub cust_pkg_setup_cost {
my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
my $where = '';
- my $comparison = '';
- if ( $opt{'classnum'} =~ /^(\d+)$/ ) {
- if ( $1 == 0 ) {
- $comparison = 'IS NULL';
- }
- else {
- $comparison = "= $1";
- }
- $where = "AND part_pkg.classnum $comparison";
+
+ if ( $opt{'classnum'} ne '' ) {
+ my $classnums = $opt{'classnum'};
+ $classnums = [ $classnums ] if !ref($classnums);
+ @$classnums = grep /^\d+$/, @$classnums;
+ $where .= ' AND COALESCE(part_pkg.classnum,0) IN ('. join(',', @$classnums).
+ ')';
}
+
$agentnum ||= $opt{'agentnum'};
my $total_sql = " SELECT SUM(part_pkg.setup_cost) ";
sub cust_pkg_recur_cost {
my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
my $where = '';
- my $comparison = '';
- if ( $opt{'classnum'} =~ /^(\d+)$/ ) {
- if ( $1 == 0 ) {
- $comparison = 'IS NULL';
- }
- else {
- $comparison = "= $1";
- }
- $where = " AND part_pkg.classnum $comparison";
+
+ if ( $opt{'classnum'} ne '' ) {
+ my $classnums = $opt{'classnum'};
+ $classnums = [ $classnums ] if !ref($classnums);
+ @$classnums = grep /^\d+$/, @$classnums;
+ $where .= ' AND COALESCE(part_pkg.classnum,0) IN ('. join(',', @$classnums).
+ ')';
}
+
$agentnum ||= $opt{'agentnum'};
# duplication of in_time_period_and_agent
# because we do it a little differently here
my @where = (
'pkgnum != 0',
$self->with_classnum($opt{'classnum'}, $opt{'use_override'}),
+ $self->with_report_option($opt{'report_optionnum'}, $opt{'use_override'}),
$self->in_time_period_and_agent($speriod, $eperiod, $agentnum),
);
- push @where, 'cust_main.refnum = '. $opt{'refnum'} if $opt{'refnum'};
+ # yuck, false laziness
+ push @where, "cust_main.refnum = ". $opt{'refnum'} if $opt{'refnum'};
+
+ push @where, $self->with_cust_classnum(%opt);
my $total_sql = "SELECT COALESCE(SUM(cust_bill_pkg.setup),0)
FROM cust_bill_pkg
my @where = (
'pkgnum != 0',
$self->with_classnum($opt{'classnum'}, $opt{'use_override'}),
+ $self->with_report_option($opt{'report_optionnum'}, $opt{'use_override'}),
);
push @where, 'cust_main.refnum = '. $opt{'refnum'} if $opt{'refnum'};
+ push @where, $self->with_cust_classnum(%opt);
+
# subtract all usage from the line item regardless of date
my $item_usage;
if ( $opt{'project'} ) {
push @where, 'cust_main.refnum = '. $opt{'refnum'} if $opt{'refnum'};
+ push @where, $self->with_cust_classnum(%opt);
+
$agentnum ||= $opt{'agentnum'};
push @where,
$self->with_classnum($opt{'classnum'}, $opt{'use_override'}),
$self->with_usageclass($opt{'usageclass'}),
+ $self->with_report_option($opt{'report_optionnum'}, $opt{'use_override'}),
;
if ( $opt{'distribute'} ) {
sub cust_bill_pkg_discount {
my( $self, $speriod, $eperiod, $agentnum, %opt ) = @_;
+ #need to do this the new multi-classnum way if it gets re-enabled
#my $where = '';
#my $comparison = '';
#if ( $opt{'classnum'} =~ /^(\d+)$/ ) {
$sql;
}
-sub for_custnum {
+sub for_opts {
my ( $self, %opt ) = @_;
- return '' unless $opt{'custnum'};
- $opt{'custnum'} =~ /^\d+$/ ? " and custnum = $opt{custnum} " : '';
+ my $sql = '';
+ if ( $opt{'custnum'} =~ /^(\d+)$/ ) {
+ $sql .= " and custnum = $1 ";
+ }
+ if ( $opt{'refnum'} =~ /^(\d+)$/ ) {
+ $sql .= " and refnum = $1 ";
+ }
+ if ( my $where = $self->with_cust_classnum(%opt) ) {
+ $sql .= " and $where";
+ }
+
+ $sql;
}
sub with_classnum {
- my $self = shift;
- my ($classnum, $use_override) = @_;
- return '' unless $classnum =~ /^\d+$/;
- my $comparison;
- if ( $classnum == 0 ) {
- $comparison = 'IS NULL';
- }
- else {
- $comparison = "= $classnum";
- }
+ my ($self, $classnum, $use_override) = @_;
+ return '' if $classnum eq '';
+
+ $classnum = [ $classnum ] if !ref($classnum);
+ @$classnum = grep /^\d+$/, @$classnum;
+ my $in = 'IN ('. join(',', @$classnum). ')';
+
if ( $use_override ) {
- return "(
- part_pkg.classnum $comparison AND pkgpart_override IS NULL OR
- override.classnum $comparison AND pkgpart_override IS NOT NULL
+ "(
+ ( COALESCE(part_pkg.classnum, 0) $in AND pkgpart_override IS NULL)
+ OR ( COALESCE(override.classnum, 0) $in AND pkgpart_override IS NOT NULL )
)";
- }
- else {
- return "part_pkg.classnum $comparison";
+ } else {
+ "COALESCE(part_pkg.classnum, 0) $in";
}
}
return "cust_bill_pkg_detail.classnum $comparison";
}
+sub with_report_option {
+ my ($self, $num, $use_override) = @_;
+ # $num can be a single number, or a comma-delimited list of numbers,
+ # or an arrayref. 0 matches the empty set
+ # or the word 'multiple' for all packages with more than one report class
+ return '' if !defined($num);
+
+ $num = join(',', @$num) if ref($num);
+
+ # stringify the set of report options for each pkgpart
+ my $table = $use_override ? 'override' : 'part_pkg';
+ my $subselect = "
+ SELECT replace(optionname, 'report_option_', '') AS num
+ FROM part_pkg_option
+ WHERE optionname like 'report_option_%'
+ AND part_pkg_option.pkgpart = $table.pkgpart
+ ORDER BY num";
+
+ my $comparison;
+ if ( $num eq 'multiple' ) {
+ $comparison = "(SELECT COUNT(*) FROM ($subselect) AS x) > 1";
+ } else {
+
+ my @num = split(/\s*,\s*/, $num);
+
+ #$comparison = "(SELECT COALESCE(string_agg(num, ','), '') FROM ( #Pg 9-ism
+ $comparison = "(SELECT COALESCE(array_to_string(array_agg(num), ','), '')
+ FROM ($subselect) AS x
+ ) = '". join(',', grep $_, @num). "'";
+
+ $comparison = "( $comparison OR NOT EXISTS ($subselect) )"
+ if grep !$_, @num;
+
+ }
+ if ( $use_override ) {
+ # then also allow the non-override package to match
+ $comparison = "( $comparison OR " . $self->with_report_option($num) . ")";
+ }
+ $comparison;
+}
+
+sub with_cust_classnum {
+ my ($self, %opt) = @_;
+ if ( $opt{'cust_classnum'} ) {
+ my $classnums = $opt{'cust_classnum'};
+ $classnums = [ $classnums ] if !ref($classnums);
+ @$classnums = grep /^\d+$/, @$classnums;
+ return 'cust_main.classnum in('. join(',',@$classnums) .')'
+ if @$classnums;
+ }
+ '';
+}
+
+
sub scalar_sql {
my( $self, $sql ) = ( shift, shift );
my $sth = dbh->prepare($sql) or die dbh->errstr;