summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjeff <jeff>2009-10-05 00:49:34 +0000
committerjeff <jeff>2009-10-05 00:49:34 +0000
commit947c1f964f1304242f8a6ffabacccf040f1d505e (patch)
treeba3e3a042f40ac4b1b660e944973a2f1b29f80fa
parent161eeea92a87e07d071a6c953f2dbd30daeb480c (diff)
leading summary page invoices #RT5086
-rw-r--r--FS/FS/Conf.pm42
-rw-r--r--FS/FS/Schema.pm3
-rw-r--r--FS/FS/Upgrade.pm3
-rw-r--r--FS/FS/cust_bill.pm129
-rw-r--r--FS/FS/cust_bill_pkg.pm5
-rw-r--r--FS/FS/cust_bill_pkg_display.pm7
-rw-r--r--FS/FS/cust_main.pm37
-rw-r--r--FS/FS/part_event/Action/cust_bill_fee_percent.pm3
-rw-r--r--FS/FS/part_event/Action/fee.pm3
-rw-r--r--FS/FS/pkg_category.pm35
-rw-r--r--conf/invoice_html167
-rw-r--r--conf/invoice_htmlsummary74
-rw-r--r--conf/invoice_latex133
-rw-r--r--conf/invoice_latexsummary45
-rw-r--r--httemplate/browse/pkg_category.html6
-rw-r--r--httemplate/edit/pkg_category.html2
16 files changed, 525 insertions, 169 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 3b37fea..1353df8 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -892,6 +892,13 @@ worry that config_items is freeside-specific and icky.
},
{
+ 'key' => 'invoice_usesummary',
+ 'section' => 'billing',
+ 'description' => 'Indicates that html and latex invoices should be in summary style and make use of invoice_latexsummary.',
+ 'type' => 'checkbox',
+ },
+
+ {
'key' => 'invoice_template',
'section' => 'billing',
'description' => 'Text template file for invoices. Used if no invoice_html template is defined, and also seen by users using non-HTML capable mail clients. See the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration#Plaintext_invoice_templates">billing documentation</a> for details.',
@@ -923,6 +930,14 @@ worry that config_items is freeside-specific and icky.
},
{
+ 'key' => 'invoice_htmlsummary',
+ 'section' => 'billing',
+ 'description' => 'Summary initial page for HTML invoices.',
+ 'type' => 'textarea',
+ 'per_agent' => 1,
+ },
+
+ {
'key' => 'invoice_htmlreturnaddress',
'section' => 'billing',
'description' => 'Return address for HTML invoices. Defaults to the same data in invoice_latexreturnaddress if not specified.',
@@ -953,6 +968,14 @@ worry that config_items is freeside-specific and icky.
},
{
+ 'key' => 'invoice_latexsummary',
+ 'section' => 'billing',
+ 'description' => 'Summary initial page for LaTeX typeset PostScript invoices.',
+ 'type' => 'textarea',
+ 'per_agent' => 1,
+ },
+
+ {
'key' => 'invoice_latexcoupon',
'section' => 'billing',
'description' => 'Remittance coupon for LaTeX typeset PostScript invoices.',
@@ -1005,6 +1028,25 @@ worry that config_items is freeside-specific and icky.
'type' => 'checkbox',
},
+ {
+ 'key' => 'finance_pkgclass',
+ 'section' => 'billing',
+ 'description' => 'The package class for finance charges',
+ 'type' => 'select-sub',
+ 'options_sub' => sub { require FS::Record;
+ require FS::pkg_class;
+ map { $_->classnum => $_->classname }
+ FS::Record::qsearch('pkg_class', {} );
+ },
+ 'option_sub' => sub { require FS::Record;
+ require FS::pkg_class;
+ my $pkg_class = FS::Record::qsearchs(
+ 'pkg_class', { 'classnum'=>shift }
+ );
+ $pkg_class ? $pkg_class->classname : '';
+ },
+ },
+
{
'key' => 'separate_usage',
'section' => 'billing',
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 4af026c..70f3250 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -394,6 +394,8 @@ sub tables_hashref {
'custnum', 'int', '', '', '', '',
'_date', @date_type, '', '',
'charged', @money_type, '', '',
+ 'previous_balance', @money_typen, '', '', #eventually not nullable
+ 'billing_balance', @money_typen, '', '', #eventually not nullable
'printed', 'int', '', '', '', '',
'closed', 'char', 'NULL', 1, '', '',
'statementnum', 'int', 'NULL', '', '', '',
@@ -2073,6 +2075,7 @@ sub tables_hashref {
'columns' => [
'categorynum', 'serial', '', '', '', '',
'categoryname', 'varchar', '', $char_d, '', '',
+ 'weight', 'int', 'NULL', '', '', '',
'disabled', 'char', 'NULL', 1, '', '',
],
'primary_key' => 'categorynum',
diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm
index 7aecf45..e5cd5d3 100644
--- a/FS/FS/Upgrade.pm
+++ b/FS/FS/Upgrade.pm
@@ -135,6 +135,9 @@ sub upgrade_data {
#change recur_flat and enable_prorate
'part_pkg_option' => [],
+ #add weights to pkg_category
+ 'pkg_category' => [],
+
;
\%hash;
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index 55faa36..eefcc80 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -1968,6 +1968,7 @@ sub print_generic {
'smallfooter' => sub { map "$_", @_ },
'returnaddress' => sub { map "$_", @_ },
'coupon' => sub { map "$_", @_ },
+ 'summary' => sub { map "$_", @_ },
},
'html' => {
'notes' =>
@@ -2001,6 +2002,7 @@ sub print_generic {
} @_
},
'coupon' => sub { "" },
+ 'summary' => sub { "" },
},
'template' => {
'notes' =>
@@ -2031,6 +2033,7 @@ sub print_generic {
} @_
},
'coupon' => sub { "" },
+ 'summary' => sub { "" },
},
);
@@ -2147,6 +2150,14 @@ sub print_generic {
'unitprices' => $conf->exists('invoice-unitprice'),
);
+ $invoice_data{finance_section} = '';
+ if ( $conf->config('finance_pkgclass') ) {
+ my $pkg_class =
+ qsearchs('pkg_class', { classnum => $conf->config('finance_pkgclass') });
+ $invoice_data{finance_section} = $pkg_class->categoryname;
+ }
+ $invoice_data{finance_amount} = '0.00';
+
my $countrydefault = $conf->config('countrydefault') || 'US';
my $prefix = $cust_main->has_ship_address ? 'ship_' : '';
foreach ( qw( contact company address1 address2 city state zip country fax) ){
@@ -2193,11 +2204,19 @@ sub print_generic {
# my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits
#my $balance_due = $self->owed + $pr_total - $cr_total;
my $balance_due = $self->owed + $pr_total;
+ $invoice_data{'true_previous_balance'} = sprintf("%.2f", $self->previous_balance);
+ $invoice_data{'balance_adjustments'} = sprintf("%.2f", $self->previous_balance - $self->billing_balance);
$invoice_data{'previous_balance'} = sprintf("%.2f", $pr_total);
$invoice_data{'balance'} = sprintf("%.2f", $balance_due);
my $agentnum = $self->cust_main->agentnum;
+ my $summarypage = '';
+ if ( $conf->exists('invoice_usesummary', $agentnum) ) {
+ $summarypage = 1;
+ }
+ $invoice_data{'summarypage'} = $summarypage;
+
#do variable substitution in notes, footer, smallfooter
foreach my $include (qw( notes footer smallfooter coupon )) {
@@ -2257,6 +2276,7 @@ sub print_generic {
'template' => '',
);
my $other_money_char = $other_money_chars{$format};
+ $invoice_data{'dollar'} = $other_money_char;
my @detail_items = ();
my @total_items = ();
@@ -2271,21 +2291,27 @@ sub print_generic {
my $previous_section = { 'description' => 'Previous Charges',
'subtotal' => $other_money_char.
sprintf('%.2f', $pr_total),
+ 'summarized' => $summarypage ? 'Y' : '',
};
my $taxtotal = 0;
my $tax_section = { 'description' => 'Taxes, Surcharges, and Fees',
- 'subtotal' => $taxtotal }; # adjusted below
+ 'subtotal' => $taxtotal, # adjusted below
+ 'summarized' => $summarypage ? 'Y' : '',
+ };
my $adjusttotal = 0;
my $adjust_section = { 'description' => 'Credits, Payments, and Adjustments',
- 'subtotal' => 0 }; # adjusted below
+ 'subtotal' => 0, # adjusted below
+ 'summarized' => $summarypage ? 'Y' : '',
+ };
my $unsquelched = $params{unsquelch_cdr} || $cust_main->squelch_cdr ne 'Y';
my $multisection = $conf->exists('invoice_sections', $cust_main->agentnum);
my $late_sections = [];
if ( $multisection ) {
- push @sections, $self->_items_sections( $late_sections );
+ push @sections,
+ $self->_items_sections( $late_sections, $summarypage, $escape_function );
}else{
push @sections, { 'description' => '', 'subtotal' => '' };
}
@@ -2330,6 +2356,10 @@ sub print_generic {
foreach my $section (@sections, @$late_sections) {
+ $invoice_data{finance_amount} = sprintf('%.2f', $section->{'subtotal'} )
+ if ( $invoice_data{finance_section} &&
+ $section->{'description'} eq $invoice_data{finance_section} );
+
$section->{'subtotal'} = $other_money_char.
sprintf('%.2f', $section->{'subtotal'})
if $multisection;
@@ -2346,6 +2376,7 @@ sub print_generic {
$options{'escape_function'} = $escape_function;
$options{'format_function'} = sub { () } unless $unsquelched;
$options{'unsquelched'} = $unsquelched;
+ $options{'summary_page'} = $summarypage;
foreach my $line_item ( $self->_items_pkg(%options) ) {
my $detail = {
@@ -2384,6 +2415,9 @@ sub print_generic {
}
+ $invoice_data{current_less_finance} =
+ sprintf('%.2f', $self->charged - $invoice_data{finance_amount} );
+
if ( $multisection && !$conf->exists('disable_previous_balance') ) {
unshift @sections, $previous_section if $pr_total;
}
@@ -2555,7 +2589,11 @@ sub print_generic {
$total->{'total_item'} = &$embolden_function($self->balance_due_msg);
$total->{'total_amount'} =
&$embolden_function(
- $other_money_char. sprintf('%.2f', $self->owed + $pr_total )
+ $other_money_char. sprintf('%.2f', $summarypage
+ ? $self->charged +
+ $self->billing_balance
+ : $self->owed + $pr_total
+ )
);
if ( $multisection ) {
$adjust_section->{'posttotal'} = $total->{'total_item'}. ' '.
@@ -2574,6 +2612,49 @@ sub print_generic {
if $unsquelched;
}
+ my @includelist = ();
+ push @includelist, 'summary' if $summarypage;
+ foreach my $include ( @includelist ) {
+
+ my $inc_file = $conf->key_orbase("invoice_${format}$include", $template);
+ my @inc_src;
+
+ if ( length( $conf->config($inc_file, $agentnum) ) ) {
+
+ @inc_src = $conf->config($inc_file, $agentnum);
+
+ } else {
+
+ $inc_file = $conf->key_orbase("invoice_latex$include", $template);
+
+ my $convert_map = $convert_maps{$format}{$include};
+
+ @inc_src = map { s/\[\@--/$delimiters{$format}[0]/g;
+ s/--\@\]/$delimiters{$format}[1]/g;
+ $_;
+ }
+ &$convert_map( $conf->config($inc_file, $agentnum) );
+
+ }
+
+ my $inc_tt = new Text::Template (
+ TYPE => 'ARRAY',
+ SOURCE => [ map "$_\n", @inc_src ],
+ DELIMITERS => $delimiters{$format},
+ ) or die "Can't create new Text::Template object: $Text::Template::ERROR";
+
+ unless ( $inc_tt->compile() ) {
+ my $error = "Can't compile $inc_file template: $Text::Template::ERROR\n";
+ warn $error. "Template:\n". join('', map "$_\n", @inc_src);
+ die $error;
+ }
+
+ $invoice_data{$include} = $inc_tt->fill_in( HASH => \%invoice_data );
+
+ $invoice_data{$include} =~ s/\n+$//
+ if ($format eq 'latex');
+ }
+
$invoice_lines = 0;
my $wasfunc = 0;
foreach ( grep /invoice_lines\(\d*\)/, @invoice_template ) { #kludgy
@@ -2850,21 +2931,30 @@ sub _date_pretty {
sub _items_sections {
my $self = shift;
my $late = shift;
+ my $summarypage = shift;
+ my $escape = shift;
my %s = ();
my %l = ();
+ my %not_tax = ();
foreach my $cust_bill_pkg ( $self->cust_bill_pkg )
{
- if ( $cust_bill_pkg->pkgnum > 0 ) {
+
my $usage = $cust_bill_pkg->usage;
foreach my $display ($cust_bill_pkg->cust_bill_pkg_display) {
+ next if ( $display->summary && $summarypage );
+
my $desc = $display->section;
my $type = $display->type;
- if ( $display->post_total ) {
+ if ( $cust_bill_pkg->pkgnum > 0 ) {
+ $not_tax{$desc} = 1;
+ }
+
+ if ( $display->post_total && !$summarypage ) {
if (! $type || $type eq 'S') {
$l{$desc} += $cust_bill_pkg->setup
if ( $cust_bill_pkg->setup != 0 );
@@ -2908,16 +2998,29 @@ sub _items_sections {
}
- }
-
}
- push @$late, map { { 'description' => $_,
+ my %cache = map { $_->categoryname => $_ }
+ qsearch( 'pkg_category', {disabled => 'Y'} );
+ $cache{$_->categoryname} = $_
+ foreach qsearch( 'pkg_category', {disabled => ''} );
+
+ push @$late, map { { 'description' => &{$escape}($_),
'subtotal' => $l{$_},
'post_total' => 1,
- } } sort keys %l;
-
- map { {'description' => $_, 'subtotal' => $s{$_}} } sort keys %s;
+ } }
+ sort { $cache{$a}->weight <=> $cache{$b}->weight } keys %l;
+
+ map { { 'description' => &{$escape}($_),
+ 'subtotal' => $s{$_},
+ 'summarized' => $not_tax{$_} ? '' : 'Y',
+ 'tax_section' => $not_tax{$_} ? '' : 'Y',
+ } }
+ sort { $cache{$a}->weight <=> $cache{$b}->weight }
+ ( $summarypage
+ ? ( grep { exists($s{$_}) || !$cache{$_}->disabled } keys %cache )
+ : ( keys %s )
+ );
}
@@ -2999,6 +3102,7 @@ sub _items_cust_bill_pkg {
my $format_function = $opt{format_function} || '';
my $unsquelched = $opt{unsquelched} || '';
my $section = $opt{section}->{description} if $opt{section};
+ my $summary_page = $opt{summary_page} || '';
my @b = ();
my ($s, $r, $u) = ( undef, undef, undef );
@@ -3018,6 +3122,7 @@ sub _items_cust_bill_pkg {
? $_->section eq $section
: 1
}
+ grep { $_->summary || !$summary_page }
$cust_bill_pkg->cust_bill_pkg_display
)
{
diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm
index 9d7aae2..c8c242e 100644
--- a/FS/FS/cust_bill_pkg.pm
+++ b/FS/FS/cust_bill_pkg.pm
@@ -361,7 +361,10 @@ sub part_pkg {
if ( $self->pkgpart_override ) {
qsearchs('part_pkg', { 'pkgpart' => $self->pkgpart_override } );
} else {
- $self->cust_pkg->part_pkg;
+ my $part_pkg;
+ my $cust_pkg = $self->cust_pkg;
+ $part_pkg = $cust_pkg->part_pkg if $cust_pkg;
+ $part_pkg;
}
}
diff --git a/FS/FS/cust_bill_pkg_display.pm b/FS/FS/cust_bill_pkg_display.pm
index 93c6e87..cf70cbd 100644
--- a/FS/FS/cust_bill_pkg_display.pm
+++ b/FS/FS/cust_bill_pkg_display.pm
@@ -52,7 +52,12 @@ sub section {
if ( defined($value) ) {
$self->setfield('section', $value);
} else {
- $self->getfield('section') || $self->cust_bill_pkg->part_pkg->categoryname;
+ my $section = $self->getfield('section');
+ unless ($section) {
+ my $part_pkg = $self->cust_bill_pkg->part_pkg;
+ $section = $part_pkg->categoryname if $part_pkg;
+ }
+ $section;
}
}
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index b5a8f0d..16ab0ee 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -2717,6 +2717,23 @@ sub bill {
$tax = sprintf('%.2f', $tax );
$total_setup = sprintf('%.2f', $total_setup+$tax );
+ my $pkg_category = qsearchs( 'pkg_category', { 'categoryname' => $taxname,
+ 'disabled' => '',
+ },
+ );
+
+ my @display = ();
+ if ( $pkg_category and
+ $conf->config('invoice_latexsummary') ||
+ $conf->config('invoice_htmlsummary')
+ )
+ {
+
+ my %hash = ( 'section' => $pkg_category->categoryname );
+ push @display, new FS::cust_bill_pkg_display { type => 'S', %hash };
+
+ }
+
push @cust_bill_pkg, new FS::cust_bill_pkg {
'pkgnum' => 0,
'setup' => $tax,
@@ -2724,6 +2741,7 @@ sub bill {
'sdate' => '',
'edate' => '',
'itemdesc' => $taxname,
+ 'display' => \@display,
'cust_bill_pkg_tax_location' => \@cust_bill_pkg_tax_location,
'cust_bill_pkg_tax_rate_location' => \@cust_bill_pkg_tax_rate_location,
};
@@ -2761,11 +2779,24 @@ sub bill {
my $charged = sprintf('%.2f', $total_setup + $total_recur );
+ my @cust_bill = $self->cust_bill;
+ my $balance = $self->balance;
+ my $previous_balance = scalar(@cust_bill)
+ ? $cust_bill[$#cust_bill]->billing_balance
+ : 0;
+
+ $previous_balance += $cust_bill[$#cust_bill]->charged
+ if scalar(@cust_bill);
+ #my $balance_adjustments =
+ # sprintf('%.2f', $balance - $prior_prior_balance - $prior_charged);
+
#create the new invoice
my $cust_bill = new FS::cust_bill ( {
- 'custnum' => $self->custnum,
- '_date' => ( $invoice_time ),
- 'charged' => $charged,
+ 'custnum' => $self->custnum,
+ '_date' => ( $invoice_time ),
+ 'charged' => $charged,
+ 'billing_balance' => $balance,
+ 'previous_balance' => $previous_balance,
} );
$error = $cust_bill->insert;
if ( $error ) {
diff --git a/FS/FS/part_event/Action/cust_bill_fee_percent.pm b/FS/FS/part_event/Action/cust_bill_fee_percent.pm
index c853393..b0397d4 100644
--- a/FS/FS/part_event/Action/cust_bill_fee_percent.pm
+++ b/FS/FS/part_event/Action/cust_bill_fee_percent.pm
@@ -31,6 +31,8 @@ sub do_action {
#my $cust_main = $self->cust_main($cust_bill);
my $cust_main = $cust_bill->cust_main;
+ my $conf = new FS::Conf;
+
my $amount =
sprintf('%.2f', $cust_bill->owed * $self->option('percent') / 100 );
@@ -38,6 +40,7 @@ sub do_action {
'amount' => $amount,
'pkg' => $self->option('reason'),
'taxclass' => $self->option('taxclass'),
+ 'classnum' => $conf->config('finance_pkgclass'),
'setuptax' => $self->option('setuptax'),
);
diff --git a/FS/FS/part_event/Action/fee.pm b/FS/FS/part_event/Action/fee.pm
index c700301..163b4fa 100644
--- a/FS/FS/part_event/Action/fee.pm
+++ b/FS/FS/part_event/Action/fee.pm
@@ -26,10 +26,13 @@ sub do_action {
my $cust_main = $self->cust_main($cust_object);
+ my $conf = new FS::Conf;
+
my %charge = (
'amount' => $self->option('charge'),
'pkg' => $self->option('reason'),
'taxclass' => $self->option('taxclass'),
+ 'classnum' => $conf->config('finance_pkgclass'),
'setuptax' => $self->option('setuptax'),
);
diff --git a/FS/FS/pkg_category.pm b/FS/FS/pkg_category.pm
index 69578c9..0beaf1c 100644
--- a/FS/FS/pkg_category.pm
+++ b/FS/FS/pkg_category.pm
@@ -1,11 +1,13 @@
package FS::pkg_category;
use strict;
-use vars qw( @ISA );
-use FS::Record qw( qsearch );
+use vars qw( @ISA $me $DEBUG );
+use FS::Record qw( qsearch dbh );
use FS::part_pkg;
@ISA = qw( FS::Record );
+$DEBUG = 0;
+$me = '[FS::pkg_category]';
=head1 NAME
@@ -95,10 +97,39 @@ sub check {
$self->ut_numbern('categorynum')
or $self->ut_text('categoryname')
+ or $self->ut_snumber('weight')
or $self->SUPER::check;
}
+# _ upgrade_data
+#
+# Used by FS::Upgrade to migrate to a new database.
+#
+#
+
+sub _upgrade_data {
+ my ($class, %opts) = @_;
+ my $dbh = dbh;
+
+ warn "$me upgrading $class\n" if $DEBUG;
+
+ my @pkg_category =
+ qsearch('pkg_category', { weight => { op => '!=', value => '' } } );
+
+ unless( scalar(@pkg_category) ) {
+ my @pkg_category = qsearch('pkg_category', {} );
+ my $weight = 0;
+ foreach ( sort { $a->description cmp $b->description } @pkg_category ) {
+ $_->weight($weight);
+ my $error = $_->replace;
+ die "error setting pkg_category weight: $error\n" if $error;
+ $weight += 10;
+ }
+ }
+ '';
+}
+
=back
=head1 BUGS
diff --git a/conf/invoice_html b/conf/invoice_html
index d5e24b8..73dcc2e 100644
--- a/conf/invoice_html
+++ b/conf/invoice_html
@@ -3,6 +3,8 @@
.invoice_header { font-size: 10pt }
.invoice_headerright TH { border-top: 2px solid #000000; border-bottom: 2px solid #000000 }
.invoice_headerright TD { font-size: 10pt; empty-cells: show }
+.invoice_summary TH { border-bottom: 2px solid #000000 }
+.invoice_summary TD { font-size: 10pt; empty-cells: show }
.invoice_longtable table { cellspacing: none }
.invoice_longtable TH { border-top: 2px solid #000000; border-bottom: 1px solid #000000; padding-left: none; padding-right: none; font-size: 10pt }
.invoice_desc TD { border-top: 2px solid #000000; font-weight: bold; font-size: 10pt }
@@ -11,7 +13,7 @@
.invoice_totaldesc TD { font-size: 10pt; empty-cells: show }
</STYLE>
-<table class="invoice" bgcolor="#ffffff" WIDTH=625 CELLSPACING=8><tr><td>
+<table class="invoice" bgcolor="#ffffff" WIDTH=768 CELLSPACING=8><tr><td>
<table class="invoice_header" width="100%">
<tr>
@@ -82,10 +84,10 @@
</tr>
</table>
-
+ <%= $summary %>
<%=
- foreach my $section ( @sections ) {
- if ($section->{'pretotal'}) {
+ foreach my $section ( grep { !$summary || $_->{description} ne $finance_section } @sections ) {
+ if ($section->{'pretotal'} && !$summary) {
$OUT .=
'<table width="100%"><tr><td>'.
'<p align="right"><b><font size="+1">'.
@@ -95,91 +97,92 @@
'<p>'.
'</td></tr></table>';
}
- $OUT .= '<table><tr><td>';
- if ($section->{'description'}) {
- $OUT .=
- '<p><b><font size="+1">'. uc(substr($section->{'description'},0,1)).
- '</font><font size="+0">'. uc(substr($section->{'description'},1)).
- '</font></b>'.
- '<p>';
- }else{
- $OUT .=
- '<p><b><font size="+1">C</font><font size="+0">HARGES</font></b>'.
- '<p>';
- }
- $OUT .= '</td></tr></table>';
+ unless ($section->{'summarized'}) {
+ $OUT .= '<table><tr><td>';
+ if ($section->{'description'}) {
+ $OUT .=
+ '<p><b><font size="+1">'. uc(substr($section->{'description'},0,1)).
+ '</font><font size="+0">'. uc(substr($section->{'description'},1)).
+ '</font></b>'.
+ '<p>';
+ }else{
+ $OUT .=
+ '<p><b><font size="+1">C</font><font size="+0">HARGES</font></b>'.
+ '<p>';
+ }
+ $OUT .= '</td></tr></table>';
- $OUT .=
- '<table class="invoice_longtable" CELLSPACING=0 WIDTH="100%">'.
- '<tr>'.
- '<th align="center">Ref</th>'.
- '<th align="left">Description</th>'.
- ( $unitprices
- ? '<th align="left">Unit Price</th>'.
- '<th align="left">Quantity</th>'
- : ''
- ).
- '<th align="right">Amount</th>'.
- '</tr>';
-
- my $lastref = 0;
- foreach my $line (
- grep { ( scalar(@sections) > 1
- ? $section->{'description'} eq $_->{'section'}->{'description'}
- : 1
- ) }
- @detail_items )
- {
$OUT .=
- '<tr class="invoice_desc'.
- ( ($line->{'ref'} && $line->{'ref'} ne $lastref) ? '' : '_more' ).
- '">'.
- '<td align="center">'.
- ( $line->{'ref'} ne $lastref ? $line->{'ref'} : '' ). '</td>'.
- '<td align="left">'. $line->{'description'}. '</td>'.
+ '<table class="invoice_longtable" CELLSPACING=0 WIDTH="100%">'.
+ '<tr>'.
+ '<th align="center">Ref</th>'.
+ '<th align="left">Description</th>'.
( $unitprices
- ? '<td align="left">'. $line->{'unit_amount'}. '</td>'.
- '<td align="left">'. $line->{'quantity'}. '</td>'
+ ? '<th align="left">Unit Price</th>'.
+ '<th align="left">Quantity</th>'
: ''
- ).
-
- '<td align="right">'. $line->{'amount'}. '</td>'.
- '</tr>'
- ;
- $lastref = $line->{'ref'};
- if ( @{$line->{'ext_description'} } ) {
- $OUT .= '<tr class="invoice_extdesc"><td></td><td';
- $OUT .= $unitprices ? ' colspan=3>' : '>';
- $OUT .= '<table width="100%">';
- foreach my $ext_desc ( @{$line->{'ext_description'} } ) {
- $OUT .=
- '<tr class="invoice_extdesc">'.
- '<td align="left" '.
- ( $ext_desc =~ /<\/?TD>/i ? '' : 'colspan=99' ). '>'.
- '&nbsp;&nbsp;'. $ext_desc.
- '</td>'.
- '</tr>'
+ ).
+ '<th align="right">Amount</th>'.
+ '</tr>';
+
+ my $lastref = 0;
+ foreach my $line (
+ grep { ( scalar(@sections) > 1
+ ? $section->{'description'} eq $_->{'section'}->{'description'}
+ : 1
+ ) }
+ @detail_items )
+ {
+ $OUT .=
+ '<tr class="invoice_desc'.
+ ( ($line->{'ref'} && $line->{'ref'} ne $lastref) ? '' : '_more' ).
+ '">'.
+ '<td align="center">'.
+ ( $line->{'ref'} ne $lastref ? $line->{'ref'} : '' ). '</td>'.
+ '<td align="left">'. $line->{'description'}. '</td>'.
+ ( $unitprices
+ ? '<td align="left">'. $line->{'unit_amount'}. '</td>'.
+ '<td align="left">'. $line->{'quantity'}. '</td>'
+ : ''
+ ).
+
+ '<td align="right">'. $line->{'amount'}. '</td>'.
+ '</tr>'
+ ;
+ $lastref = $line->{'ref'};
+ if ( @{$line->{'ext_description'} } ) {
+ $OUT .= '<tr class="invoice_extdesc"><td></td><td';
+ $OUT .= $unitprices ? ' colspan=3>' : '>';
+ $OUT .= '<table width="100%">';
+ foreach my $ext_desc ( @{$line->{'ext_description'} } ) {
+ $OUT .=
+ '<tr class="invoice_extdesc">'.
+ '<td align="left" '.
+ ( $ext_desc =~ /<\/?TD>/i ? '' : 'colspan=99' ). '>'.
+ '&nbsp;&nbsp;'. $ext_desc.
+ '</td>'.
+ '</tr>'
+ }
+ $OUT .= '</table></td><td></td></tr>';
}
- $OUT .= '</table></td><td></td></tr>';
}
- }
- if (scalar(@sections) > 1) {
- my $style = 'border-top: 3px solid #000000;'.
- 'border-bottom: 3px solid #000000;';
- $OUT .=
- '<tr class="invoice_totaldesc">'.
- qq(<td style="$style">&nbsp;</td>).
- qq(<td align="left" style="$style").
- ( $unitprices ? ' colspan=3>' : '>' ).
- $section->{'description'}. ' Total </td>'.
- qq(<td align="right" style="$style">).
- $section->{'subtotal'}. '</td>'.
- '</tr>'
- ;
- }
-
+ if (scalar(@sections) > 1) {
+ my $style = 'border-top: 3px solid #000000;'.
+ 'border-bottom: 3px solid #000000;';
+ $OUT .=
+ '<tr class="invoice_totaldesc">'.
+ qq(<td style="$style">&nbsp;</td>).
+ qq(<td align="left" style="$style").
+ ( $unitprices ? ' colspan=3>' : '>' ).
+ $section->{'description'}. ' Total </td>'.
+ qq(<td align="right" style="$style">).
+ $section->{'subtotal'}. '</td>'.
+ '</tr>'
+ ;
+ }
+ }
if ($section->{'posttotal'}) {
$OUT .= '<tr><td align="right" colspan=5>';
$OUT .=
@@ -218,7 +221,7 @@
</table>
<br><br>
-<%= $notes %>
+<%= length($summary) ? '' : $notes %>
<hr NOSHADE SIZE=2 COLOR="#000000">
<p align="center"><%= $footer %>
diff --git a/conf/invoice_htmlsummary b/conf/invoice_htmlsummary
new file mode 100644
index 0000000..b158478
--- /dev/null
+++ b/conf/invoice_htmlsummary
@@ -0,0 +1,74 @@
+<table>
+ <tr>
+ <td>
+ <table>
+ <tr><td><%= $notes %></td></tr>
+ </table>
+ </td>
+ <td>
+ <table class="invoice_summary">
+ <tr><th colspan=2><br></th></tr>
+ <tr>
+ <td><b><u><br>Summary of Previous Balance and Payments<br></u></b></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><b>Previous Balance</b></td>
+ <td align="right"><b><%= $dollar.$true_previous_balance %></b></td>
+ </tr>
+ <tr>
+ <td><b>Payments</b></td>
+ <th align="right"><b><%= $dollar.$balance_adjustments %></b></th>
+ </tr>
+ <tr>
+ <td><b>Balance Outstanding</b></td>
+ <td align="right"><b><%= $dollar.sprintf('%.2f', $true_previous_balance - $balance_adjustments) %></b></td>
+ </tr>
+ <tr><th colspan=2><br></th></tr>
+ <tr><td colspan=2><br></td></tr>
+ <tr>
+ <td><b><u>Summary of New Charges</u></b></td>
+ <td></td>
+ </tr>
+ <tr><td colspan=2><br></td></tr>
+ <%=
+ my ($last) = grep { $_->{tax_section} || !$_->{summarized} and !($finance_section && $_->{'description'} eq $finance_section)} reverse @sections;
+
+ foreach my $section ( grep { $_->{tax_section} || !$_->{summarized} and !($finance_section && $_->{'description'} eq $finance_section)} @sections ) {
+ $OUT .= '<tr><td><b>'. ($section->{'description'} ? $section->{'description'} : 'Charges' ). '</b></td>';
+ my $celltype = ($last == $section) ? 'th' : 'td';
+ $OUT .= qq(<$celltype align="right"><b>). $section->{'subtotal'}. "</b></$celltype></tr>";
+ }
+ %>
+ <tr>
+ <td><b>New Charges Total</b></td>
+ <td align="right"><b><%= $dollar.$current_less_finance %></b></td>
+ </tr>
+ <tr><th colspan=2><br></th></tr>
+ <tr><td colspan=2><br></td></tr>
+ <tr>
+ <td><b><u>Invoice Summary</u></b></td>
+ <td></td>
+ </tr>
+ <tr><td colspan=2><br></td></tr>
+ <tr>
+ <td><b>Previous Past Due Charges</b></td>
+ <td align="right"><b><%= $dollar.sprintf('%.2f', $true_previous_balance - $balance_adjustments) %></b></td>
+ </tr>
+ <tr>
+ <td><b>Finance charges on overdue amount</b></td>
+ <td align="right"><b><%= $dollar.$finance_amount %></b></td>
+ </tr>
+ <tr>
+ <td><b>New Charges</b></td>
+ <th align="right"><b><%= $dollar.$current_less_finance %></b></th>
+ </tr>
+ <tr>
+ <td><b>Total Amount Due</b></td>
+ <td align="right"><b><%= $dollar.sprintf('%.2f', $true_previous_balance + $current_charges - $balance_adjustments) %></b></td>
+ </tr>
+ <tr><th colspan=2><br></th></tr>
+ </table>
+ </td>
+ </tr>
+</table>
diff --git a/conf/invoice_latex b/conf/invoice_latex
index 7facc19..cf684ef 100644
--- a/conf/invoice_latex
+++ b/conf/invoice_latex
@@ -19,7 +19,7 @@
\documentclass[letterpaper]{article}
-\usepackage{fancyhdr,lastpage,ifthen,fslongtable,afterpage,caption,multirow,bigstrut}
+\usepackage{fancyhdr,lastpage,ifthen,array,fslongtable,afterpage,caption,multirow,bigstrut}
\usepackage{graphicx} % required for logo graphic
\addtolength{\voffset}{-0.0cm} % top margin to top of header
@@ -232,83 +232,86 @@ Terms: [@-- $terms --@]\\
\end{minipage}}
\vspace{1.5cm}
%
+[@-- $summary --@]
+%
\section*{}
[@--
- foreach my $section ( @sections ) {
- if ($section->{'pretotal'}) {
+ foreach my $section ( grep { !$summary || $_->{description} ne $finance_section } @sections ) {
+ if ($section->{'pretotal'} && !$summary) {
$OUT .= '\begin{flushright}';
$OUT .= '\large\textsc{'. $section->{'pretotal'}. '}\\\\';
$OUT .= '\\end{flushright}';
}
$OUT .= '\pagebreak' if $section{'post_total'};
- $OUT .= '\captionsetup{singlelinecheck=false,justification=raggedright,font={Large,sc,bf}}';
- $OUT .= '\ifthenelse{\equal{\thepage}{1}}{\setlength{\LTextracouponspace}{\extracouponspace}}{\setlength{\LTextracouponspace}{0pt}}'
- if $coupon;
- $OUT .= '\begin{longtable}{cllllllr}';
- $OUT .= '\caption*{ ';
- $OUT .= ($section->{'description'}) ? $section->{'description'}: 'Charges';
- $OUT .= '}\\\\';
- $OUT .= '\FShead';
- $OUT .= '\endfirsthead';
- $OUT .= '\multicolumn{7}{r}{\rule{0pt}{2.5ex}Continued from previous page}\\\\';
- $OUT .= '\FShead';
- $OUT .= '\endhead';
- $OUT .= '\multicolumn{7}{r}{\rule{0pt}{2.5ex}Continued on next page...}\\\\';
- $OUT .= '\endfoot';
- $OUT .= '\hline';
-
- if (scalar(@sections) > 1) {
- $OUT .= '\FStotaldesc{' . $section->{'description'} . ' Total}' .
- '{' . $section->{'subtotal'} . '}' . "\n";
- }
-
- #if ($section == $sections[$#sections]) {
- foreach my $line (grep {$_->{section}->{description} eq $section->{description}} @total_items) {
- $OUT .= '\FStotaldesc{' . $line->{'total_item'} . '}' .
- '{' . $line->{'total_amount'} . '}' . "\n";
+ unless ($section->{'summarized'} ) {
+ $OUT .= '\captionsetup{singlelinecheck=false,justification=raggedright,font={Large,sc,bf}}';
+ $OUT .= '\ifthenelse{\equal{\thepage}{1}}{\setlength{\LTextracouponspace}{\extracouponspace}}{\setlength{\LTextracouponspace}{0pt}}'
+ if $coupon;
+ $OUT .= '\begin{longtable}{cllllllr}';
+ $OUT .= '\caption*{ ';
+ $OUT .= ($section->{'description'}) ? $section->{'description'}: 'Charges';
+ $OUT .= '}\\\\';
+ $OUT .= '\FShead';
+ $OUT .= '\endfirsthead';
+ $OUT .= '\multicolumn{7}{r}{\rule{0pt}{2.5ex}Continued from previous page}\\\\';
+ $OUT .= '\FShead';
+ $OUT .= '\endhead';
+ $OUT .= '\multicolumn{7}{r}{\rule{0pt}{2.5ex}Continued on next page...}\\\\';
+ $OUT .= '\endfoot';
+ $OUT .= '\hline';
+
+ if (scalar(@sections) > 1) {
+ $OUT .= '\FStotaldesc{' . $section->{'description'} . ' Total}' .
+ '{' . $section->{'subtotal'} . '}' . "\n";
}
- #}
-
- $OUT .= '\hline';
- $OUT .= '\endlastfoot';
-
- my $lastref = 0;
- foreach my $line (
- grep { ( scalar( @sections ) > 1
- ? $section->{'description'} eq $_->{'section'}->{'description'}
- : 1
- ) }
- @detail_items )
- {
- my $ext_description = $line->{'ext_description'};
+
+ #if ($section == $sections[$#sections]) {
+ foreach my $line (grep {$_->{section}->{description} eq $section->{description}} @total_items) {
+ $OUT .= '\FStotaldesc{' . $line->{'total_item'} . '}' .
+ '{' . $line->{'total_amount'} . '}' . "\n";
+ }
+ #}
+
+ $OUT .= '\hline';
+ $OUT .= '\endlastfoot';
+
+ my $lastref = 0;
+ foreach my $line (
+ grep { ( scalar( @sections ) > 1
+ ? $section->{'description'} eq $_->{'section'}->{'description'}
+ : 1
+ ) }
+ @detail_items )
+ {
+ my $ext_description = $line->{'ext_description'};
- # Don't break-up small packages.
- my $rowbreak = @$ext_description < 5 ? '*' : '';
+ # Don't break-up small packages.
+ my $rowbreak = @$ext_description < 5 ? '*' : '';
- $OUT .= "\\hline\n" if ($line->{'ref'} && $line->{'ref'} ne $lastref);
- $OUT .= '\FSdesc'.
- '{' . ( $line->{'ref'} ne $lastref ? $line->{'ref'} : '' ) . '}'.
- '{' . $line->{'description'} . '}' .
- '{' . ( $unitprices ? $line->{'unit_amount'} : '' ) . '}'.
- '{' . ( $unitprices ? $line->{'quantity'} : '' ) . '}' .
- '{' . $line->{'amount'} . "}${rowbreak}\n";
- $lastref = $line->{'ref'};
-
- foreach my $ext_desc (@$ext_description) {
- if ( $ext_desc !~ /[^\\]&/ ) {
- $ext_desc = substr($ext_desc, 0, 80) . '...'
- if (length($ext_desc) > 80);
- $ext_desc = '\multicolumn{6}{l}{\small{~~~'. $ext_desc. '}}';
- }else{
- $ext_desc = "~~~$ext_desc";
+ $OUT .= "\\hline\n" if ($line->{'ref'} && $line->{'ref'} ne $lastref);
+ $OUT .= '\FSdesc'.
+ '{' . ( $line->{'ref'} ne $lastref ? $line->{'ref'} : '' ) . '}'.
+ '{' . $line->{'description'} . '}' .
+ '{' . ( $unitprices ? $line->{'unit_amount'} : '' ) . '}'.
+ '{' . ( $unitprices ? $line->{'quantity'} : '' ) . '}' .
+ '{' . $line->{'amount'} . "}${rowbreak}\n";
+ $lastref = $line->{'ref'};
+
+ foreach my $ext_desc (@$ext_description) {
+ if ( $ext_desc !~ /[^\\]&/ ) {
+ $ext_desc = substr($ext_desc, 0, 80) . '...'
+ if (length($ext_desc) > 80);
+ $ext_desc = '\multicolumn{6}{l}{\small{~~~'. $ext_desc. '}}';
+ }else{
+ $ext_desc = "~~~$ext_desc";
+ }
+ $OUT .= '\FSextdesc{' . $ext_desc . '}' . "${rowbreak}\n";
}
- $OUT .= '\FSextdesc{' . $ext_desc . '}' . "${rowbreak}\n";
+
}
+ $OUT .= '\end{longtable}';
}
-
- $OUT .= '\end{longtable}';
-
if ($section->{'posttotal'}) {
$OUT .= '\begin{flushright}';
$OUT .= '\normalfont\large\bfseries\textsc{'. $section->{'posttotal'}. '}\\\\';
@@ -319,7 +322,7 @@ Terms: [@-- $terms --@]\\
--@]
\vfill
\begin{minipage}[t]{\textwidth}
- [@-- $notes --@]
+ [@-- length($summary) ? '' : $notes --@]
[@-- $coupon ? '\ifthenelse{\equal{\thepage}{1}}{\rule{0pt}{\extracouponspace}}{}' : '' --@]
\end{minipage}
\end{document}
diff --git a/conf/invoice_latexsummary b/conf/invoice_latexsummary
new file mode 100644
index 0000000..a181ee4
--- /dev/null
+++ b/conf/invoice_latexsummary
@@ -0,0 +1,45 @@
+\begin{tabular}{ll}
+\begin{minipage}{6.4cm}
+\begin{tabular}{m{0cm}m{6.4cm}}
+\rule{0cm}{10cm}&\begin{minipage}{6cm}[@-- $notes --@]\end{minipage}\\
+\end{tabular}
+\end{minipage} &
+\rule{2cm}{0cm}
+\begin{minipage}{12.8cm}
+\begin{tabular}{lr}
+\hline
+&\\
+\textbf{\underline{Summary of Previous Balance and Payments}} & \\
+&\\
+\textbf{Previous Balance}&\textbf{\dollar[@-- $true_previous_balance --@]}\\
+\textbf{Payments}&\textbf{\dollar[@-- $balance_adjustments --@]}\\
+\cline{2-2}
+\textbf{Balance Outstanding}&\textbf{\dollar[@-- sprintf('%.2f', $true_previous_balance -$balance_adjustments) --@]}\\
+&\\
+\hline
+&\\
+\textbf{\underline{Summary of New Charges}} & \\
+&\\
+[@--
+ foreach my $section ( grep { $_->{tax_section} || !$_->{summarized} and !($finance_section && $_->{'description'} eq $finance_section)} @sections ) {
+ $OUT .= '\textbf{'. ($section->{'description'} ? $section->{'description'} : 'Charges' ). '}';
+ $OUT .= '&\textbf{'. $section->{'subtotal'}. '}\\\\';
+ }
+ $OUT .= '\cline{2-2}';
+--@]
+\textbf{New Charges Total}&\textbf{\dollar[@-- $current_less_finance --@]}\\
+&\\
+\hline
+&\\
+\textbf{\underline{Invoice Summary}} & \\
+& \\
+\textbf{Previous Past Due Charges}&\textbf{\dollar[@-- sprintf('%.2f', $true_previous_balance - $balance_adjustments) --@]}\\
+\textbf{Finance charges on overdue amount}&\textbf{\dollar[@-- $finance_amount --@]}\\
+\textbf{New Charges}&\textbf{\dollar[@-- $current_less_finance --@]}\\
+\cline{2-2}
+\textbf{Total Amount Due}&\textbf{\dollar[@-- sprintf('%.2f', $true_previous_balance + $current_charges - $balance_adjustments) --@]}\\
+&\\
+\hline
+\end{tabular}
+\end{minipage} \\
+\end{tabular}
diff --git a/httemplate/browse/pkg_category.html b/httemplate/browse/pkg_category.html
index 20bf1a8..e85c0dd 100644
--- a/httemplate/browse/pkg_category.html
+++ b/httemplate/browse/pkg_category.html
@@ -9,9 +9,9 @@
'extra_sql' => 'ORDER BY categorynum',
},
'count_query' => $count_query,
- 'header' => [ '#', 'Category' ],
- 'fields' => [ 'categorynum', 'categoryname' ],
- 'links' => [ $link, $link ],
+ 'header' => [ '#', 'Category', 'Weight' ],
+ 'fields' => [ 'categorynum', 'categoryname', 'weight' ],
+ 'links' => [ $link, $link, $link ],
)
%>
diff --git a/httemplate/edit/pkg_category.html b/httemplate/edit/pkg_category.html
index fdc8da6..a07dc58 100644
--- a/httemplate/edit/pkg_category.html
+++ b/httemplate/edit/pkg_category.html
@@ -3,11 +3,13 @@
'table' => 'pkg_category',
'fields' => [
'categoryname',
+ 'weight',
{ field=>'disabled', type=>'checkbox', value=>'Y', },
],
'labels' => {
'categorynum' => 'Category number',
'categoryname' => 'Category name',
+ 'weight' => 'Weight',
'disabled' => 'Disable category',
},
'viewall_dir' => 'browse',