summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Prykop <jonathan@freeside.biz>2015-01-28 19:28:13 -0600
committerJonathan Prykop <jonathan@freeside.biz>2015-01-28 19:28:13 -0600
commit92a327b2bc09344a7e0db93f40e34b71547bf075 (patch)
tree5dd0ea80b997a3a1b003e0dac52463aa20ac96d5
parent730a14abf09f1ed8854cfded6f432fee832ea7d8 (diff)
parent3ed9d0fa90662f037f3fb2f50632ccb34066a979 (diff)
Merge branch 'master' of git.freeside.biz:/home/git/freeside
-rw-r--r--FS/FS/Conf.pm2
-rw-r--r--FS/FS/Report/Tax.pm16
-rw-r--r--FS/FS/Schema.pm15
-rw-r--r--FS/FS/Template_Mixin.pm40
-rw-r--r--FS/FS/contact_email.pm1
-rw-r--r--FS/FS/cust_main.pm4
-rw-r--r--FS/FS/cust_main_note.pm1
-rw-r--r--FS/FS/cust_pay.pm9
-rw-r--r--FS/FS/discount.pm7
-rw-r--r--FS/FS/prospect_main.pm5
-rwxr-xr-xhttemplate/edit/cust_main_note.cgi27
-rwxr-xr-xhttemplate/edit/part_pkg.cgi13
-rw-r--r--httemplate/edit/process/bulk-svc_phone.html2
-rwxr-xr-xhttemplate/edit/process/cust_main_note.cgi1
-rw-r--r--httemplate/search/report_tax.cgi7
-rw-r--r--httemplate/view/cust_main/notes/notes.html18
-rw-r--r--httemplate/view/cust_main/payment_history/voided_invoice.html2
-rw-r--r--httemplate/view/cust_main/payment_history/voided_payment.html2
18 files changed, 115 insertions, 57 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 279a4dfe8..239e304dd 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -773,7 +773,7 @@ sub reason_type_options {
{
'key' => 'log_sent_mail',
'section' => 'notification',
- 'description' => 'Enable logging of template-generated email.',
+ 'description' => 'Enable logging of all sent email.',
'type' => 'checkbox',
},
diff --git a/FS/FS/Report/Tax.pm b/FS/FS/Report/Tax.pm
index f3f441d21..23c16452e 100644
--- a/FS/FS/Report/Tax.pm
+++ b/FS/FS/Report/Tax.pm
@@ -41,13 +41,9 @@ sub report_internal {
my ($taxname, $country, %breakdown);
- # purify taxname properly here, as we're going to include it in lots of
- # SQL statements using single quotes only
- if ( $opt{taxname} =~ /^([\w\s]+)$/ ) {
- $taxname = $1;
- } else {
- die "taxname required"; # UI prevents this
- }
+ # taxname can contain arbitrary punctuation; escape it properly and
+ # include $taxname unquoted elsewhere
+ $taxname = dbh->quote($opt{'taxname'});
if ( $opt{country} =~ /^(\w\w)$/ ) {
$country = $1;
@@ -103,7 +99,7 @@ sub report_internal {
GROUP BY billpkgnum, taxnum";
my $where = "WHERE cust_bill._date >= $beginning AND cust_bill._date <= $ending ".
- "AND COALESCE(cust_main_county.taxname,'Tax') = '$taxname' ".
+ "AND COALESCE(cust_main_county.taxname,'Tax') = $taxname ".
"AND cust_main_county.country = '$country'";
# SELECT/GROUP clauses for first-level queries
my $select = "SELECT ";
@@ -370,14 +366,14 @@ sub report_internal {
SELECT 1 FROM cust_tax_exempt_pkg
JOIN cust_main_county USING (taxnum)
WHERE cust_tax_exempt_pkg.billpkgnum = cust_bill_pkg.billpkgnum
- AND COALESCE(cust_main_county.taxname,'Tax') = '$taxname'
+ AND COALESCE(cust_main_county.taxname,'Tax') = $taxname
AND cust_tax_exempt_pkg.creditbillpkgnum IS NULL
)
AND NOT EXISTS(
SELECT 1 FROM cust_bill_pkg_tax_location
JOIN cust_main_county USING (taxnum)
WHERE cust_bill_pkg_tax_location.taxable_billpkgnum = cust_bill_pkg.billpkgnum
- AND COALESCE(cust_main_county.taxname,'Tax') = '$taxname'
+ AND COALESCE(cust_main_county.taxname,'Tax') = $taxname
)
";
warn "\nOUTSIDE:\n$sql_outside\n" if $DEBUG;
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index ca6d169e5..b7611c154 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -2013,13 +2013,14 @@ sub tables_hashref {
'cust_main_note' => {
'columns' => [
- 'notenum', 'serial', '', '', '', '',
- 'custnum', 'int', '', '', '', '',
- 'classnum', 'int', 'NULL', '', '', '',
- '_date', @date_type, '', '',
- 'otaker', 'varchar', 'NULL', 32, '', '',
- 'usernum', 'int', 'NULL', '', '', '',
- 'comments', 'text', 'NULL', '', '', '',
+ 'notenum', 'serial', '', '', '', '',
+ 'custnum', 'int', '', '', '', '',
+ 'classnum', 'int', 'NULL', '', '', '',
+ '_date', @date_type, '', '',
+ 'otaker', 'varchar', 'NULL', 32, '', '',
+ 'usernum', 'int', 'NULL', '', '', '',
+ 'comments', 'text', 'NULL', '', '', '',
+ 'sticky', 'int', '', '', 0, '',
],
'primary_key' => 'notenum',
'unique' => [],
diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm
index 1fed7f1b9..9669ac2cf 100644
--- a/FS/FS/Template_Mixin.pm
+++ b/FS/FS/Template_Mixin.pm
@@ -347,8 +347,8 @@ sub print_generic {
if ( $format eq 'latex' && grep { /^%%Detail/ } @invoice_template ) {
#change this to a die when the old code is removed
- # it's been almost ten years, changing it to a die on the next release.
- warn "old-style invoice template $templatefile; ".
+ # it's been almost ten years, changing it to a die
+ die "old-style invoice template $templatefile; ".
"patch with conf/invoice_latex.diff or use new conf/invoice_latex*\n";
#$old_latex = 'true';
#@invoice_template = _translate_old_latex_format(@invoice_template);
@@ -1172,6 +1172,12 @@ sub print_generic {
join(', ', map "$_=>".$line_item->{$_}, keys %$line_item). "\n"
if $DEBUG > 1;
+ push @buf, ( [ $line_item->{'description'},
+ $money_char. sprintf("%10.2f", $line_item->{'amount'}),
+ ],
+ map { [ " ". $_, '' ] } @{$line_item->{'ext_description'}},
+ );
+
$line_item->{'ref'} = $line_item->{'pkgnum'};
$line_item->{'product_code'} = $line_item->{'pkgpart'} || 'N/A'; # mt()?
$line_item->{'section'} = $section;
@@ -1184,11 +1190,6 @@ sub print_generic {
$line_item->{'ext_description'} ||= [];
push @detail_items, $line_item;
- push @buf, ( [ $line_item->{'description'},
- $money_char. sprintf("%10.2f", $line_item->{'amount'}),
- ],
- map { [ " ". $_, '' ] } @{$line_item->{'ext_description'}},
- );
}
if ( $section->{'description'} ) {
@@ -3448,8 +3449,29 @@ sub _items_cust_bill_pkg {
ext_description => \@ext,
};
foreach my $cust_bill_pkg_discount (@discounts) {
- my $def = $cust_bill_pkg_discount->cust_pkg_discount->discount;
- push @ext, &{$escape_function}( $def->description );
+ my $discount = $cust_bill_pkg_discount->cust_pkg_discount->discount;
+ my $discount_desc = $discount->description_short;
+
+ if ($discount->months) {
+
+ # calculate months remaining after this invoice
+ my $used = FS::Record->scalar_sql(
+ 'SELECT SUM(months) FROM cust_bill_pkg_discount
+ JOIN cust_bill_pkg USING (billpkgnum)
+ JOIN cust_bill USING (invnum)
+ WHERE pkgdiscountnum = ? AND _date <= ?',
+ $cust_bill_pkg_discount->pkgdiscountnum,
+ $self->_date
+ );
+ $used ||= 0;
+ my $remaining = sprintf('%.2f', $discount->months - $used);
+ # append "for X months (Y months remaining)"
+ $discount_desc .= $self->mt(' for [quant,_1,month] ([quant,_2,month] remaining)',
+ $cust_bill_pkg_discount->months,
+ $remaining
+ );
+ } # else it's not time-limited
+ push @ext, &{$escape_function}($discount_desc);
}
}
diff --git a/FS/FS/contact_email.pm b/FS/FS/contact_email.pm
index a0ff27393..8d6bbbf6f 100644
--- a/FS/FS/contact_email.pm
+++ b/FS/FS/contact_email.pm
@@ -2,6 +2,7 @@ package FS::contact_email;
use base qw( FS::Record );
use strict;
+use FS::Msgcat qw( gettext );
=head1 NAME
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index e4766f52b..1ed1d4ace 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -2139,8 +2139,8 @@ Returns all notes (see L<FS::cust_main_note>) for this customer.
sub notes {
my($self,$orderby_classnum) = (shift,shift);
- my $orderby = "_DATE DESC";
- $orderby = "CLASSNUM ASC, $orderby" if $orderby_classnum;
+ my $orderby = "sticky DESC, _date DESC";
+ $orderby = "classnum ASC, $orderby" if $orderby_classnum;
qsearch( 'cust_main_note',
{ 'custnum' => $self->custnum },
'',
diff --git a/FS/FS/cust_main_note.pm b/FS/FS/cust_main_note.pm
index 712580764..ee63883d2 100644
--- a/FS/FS/cust_main_note.pm
+++ b/FS/FS/cust_main_note.pm
@@ -112,6 +112,7 @@ sub check {
|| $self->ut_numbern('_date')
|| $self->ut_textn('otaker')
|| $self->ut_anything('comments')
+ || $self->ut_numbern('sticky')
;
return $error if $error;
diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm
index 0020a824d..e44278d92 100644
--- a/FS/FS/cust_pay.pm
+++ b/FS/FS/cust_pay.pm
@@ -945,10 +945,11 @@ sub _upgrade_data { #class method
#not the most efficient, but hey, it only has to run once
- my $where = "WHERE ( otaker IS NULL OR otaker = '' OR otaker = 'ivan' ) ".
- " AND usernum IS NULL ".
- " AND 0 < ( SELECT COUNT(*) FROM cust_main ".
- " WHERE cust_main.custnum = cust_pay.custnum ) ";
+ my $where = " WHERE ( otaker IS NULL OR otaker = '' OR otaker = 'ivan' )
+ AND usernum IS NULL
+ AND EXISTS ( SELECT 1 FROM cust_main
+ WHERE cust_main.custnum = cust_pay.custnum )
+ ";
my $count_sql = "SELECT COUNT(*) FROM cust_pay $where";
diff --git a/FS/FS/discount.pm b/FS/FS/discount.pm
index 0561f9ca0..361e0b4b2 100644
--- a/FS/FS/discount.pm
+++ b/FS/FS/discount.pm
@@ -173,7 +173,12 @@ sub description_short {
my $conf = new FS::Conf;
my $money_char = $conf->config('money_char') || '$';
- my $desc = $self->name ? $self->name.': ' : '';
+ my $desc;
+ if ( $self->name ) {
+ $desc = $self->name . ': ';
+ } else {
+ $desc = 'Discount of ';
+ }
$desc .= $money_char. sprintf('%.2f/month', $self->amount)
if $self->amount > 0;
diff --git a/FS/FS/prospect_main.pm b/FS/FS/prospect_main.pm
index f30508d34..b160343de 100644
--- a/FS/FS/prospect_main.pm
+++ b/FS/FS/prospect_main.pm
@@ -405,6 +405,11 @@ sub search {
}
+# stub this so that calling ->cust_bill doesn't return an empty string
+sub cust_bill {
+ return;
+}
+
=back
=head1 BUGS
diff --git a/httemplate/edit/cust_main_note.cgi b/httemplate/edit/cust_main_note.cgi
index 61590566c..a089db2d1 100755
--- a/httemplate/edit/cust_main_note.cgi
+++ b/httemplate/edit/cust_main_note.cgi
@@ -18,17 +18,24 @@
<BR>
% }
-% if( $FS::CurrentUser::CurrentUser->option('disable_html_editor') ) {
- <TEXTAREA NAME="comment_plain" ROWS="12" COLS="60"><%
- join '', split /<br \/>|&nbsp;/, $comment
- %></TEXTAREA>
-% }
-% else {
-<% include('/elements/htmlarea.html', 'field' => 'comment_html',
- 'curr_value' => $comment) %>
+% if ( $FS::CurrentUser::CurrentUser->option('disable_html_editor') ) {
+ <TEXTAREA NAME="comment_plain" ROWS="12" COLS="60"><%
+ join '', split /<br \/>|&nbsp;/, $comment
+ %></TEXTAREA>
+% } else {
+ <& /elements/htmlarea.html, 'field' => 'comment_html',
+ 'curr_value' => $comment
+ &>
% }
-<BR><BR>
+<BR>
+
+<& /elements/checkbox.html, 'field' => 'sticky',
+ 'value' => 1,
+ 'curr_value' => $sticky,
+&>
+Sticky note<BR><BR>
+
<INPUT TYPE="submit" VALUE="<% $notenum ? emt("Apply changes") : emt("Add Note") %>">
</FORM>
@@ -42,6 +49,7 @@ my $conf = new FS::Conf;
my $comment;
my $notenum = '';
my $classnum;
+my $sticky = 0;
if ( $cgi->param('error') ) {
$comment = $cgi->param('comment');
$classnum = $cgi->param('classnum');
@@ -52,6 +60,7 @@ if ( $cgi->param('error') ) {
die "no such note: ". $notenum unless $note;
$comment = $note->comments;
$classnum = $note->classnum;
+ $sticky = $note->sticky;
}
$comment =~ s/\r//g; # remove weird line breaks to protect FCKeditor
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index 778a0265e..1702a6dc7 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -967,8 +967,17 @@ my $html_bottom = sub {
'msg' => q|You must set the 'suspend_credit_type' option in Configuration->Settings to gain access to this option.|,
'are_met' => sub{
my $conf = new FS::conf;
- my @suspend_credit_type_conf = qsearch('conf', { 'name' => 'suspend_credit_type' } );
- return 1 if (exists($suspend_credit_type_conf[0]) && $suspend_credit_type_conf[0]->{Hash}{value});
+ my @conf_info = qsearch('conf', { 'name' => 'suspend_credit_type' } );
+ return 1 if (exists($conf_info[0]) && $conf_info[0]->{Hash}{value});
+ return 0;
+ }
+ },
+ 'unused_credit_cancel' => {
+ 'msg' => q|You must set the 'cancel_credit_type' option in Configuration->Settings to gain access to this option.|,
+ 'are_met' => sub{
+ my $conf = new FS::conf;
+ my @conf_info = qsearch('conf', { 'name' => 'cancel_credit_type' } );
+ return 1 if (exists($conf_info[0]) && $conf_info[0]->{Hash}{value});
return 0;
}
}
diff --git a/httemplate/edit/process/bulk-svc_phone.html b/httemplate/edit/process/bulk-svc_phone.html
index 5a1fbc647..db486de76 100644
--- a/httemplate/edit/process/bulk-svc_phone.html
+++ b/httemplate/edit/process/bulk-svc_phone.html
@@ -25,7 +25,7 @@ my $num_avail = $1;
errorpage("There are only $num_avail available")
if $end - $start + 1 > $num_avail;
-foreach my $phonenum ( $start .. $end ) {
+foreach my $phonenum ( "$start" .. "$end" ) {
my $svc_phone = new FS::svc_phone {
'phonenum' => $phonenum,
diff --git a/httemplate/edit/process/cust_main_note.cgi b/httemplate/edit/process/cust_main_note.cgi
index 227297eef..53e616a43 100755
--- a/httemplate/edit/process/cust_main_note.cgi
+++ b/httemplate/edit/process/cust_main_note.cgi
@@ -33,6 +33,7 @@ my $new = new FS::cust_main_note ( {
_date => time,
usernum => $FS::CurrentUser::CurrentUser->usernum,
comments => $comment,
+ sticky => scalar( $cgi->param('sticky') ),
} );
my $error;
diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi
index 83f2fc5d3..491cd42c5 100644
--- a/httemplate/search/report_tax.cgi
+++ b/httemplate/search/report_tax.cgi
@@ -151,7 +151,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px }
<% emt('Out of taxable region') %>
</TD>
<TD STYLE="text-align: right">
- <A HREF="<% $saleslink %>;out=1;taxname=<% $params{taxname} %>">
+ <A HREF="<% $saleslink %>;out=1;taxname=<% encode_entities($params{'taxname'}) %>">
<% $money_sprintf->( $report->{outside } ) %>
</A>
</TD>
@@ -188,8 +188,9 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
$agentname = $agent->agentname;
}
-if ( $cgi->param('taxname') =~ /^([\w ]+)$/ ) {
- $params{taxname} = $1;
+# allow anything in here; FS::Report::Tax will treat it as unsafe
+if ( length($cgi->param('taxname')) ) {
+ $params{taxname} = $cgi->param('taxname');
} else {
die "taxname required";
}
diff --git a/httemplate/view/cust_main/notes/notes.html b/httemplate/view/cust_main/notes/notes.html
index 6a7a06a02..fa45a68f2 100644
--- a/httemplate/view/cust_main/notes/notes.html
+++ b/httemplate/view/cust_main/notes/notes.html
@@ -34,6 +34,10 @@
% my $bgcolor1 = '#eeeeee';
% my $bgcolor2 = '#ffffff';
+% my %sticky_color = ( '#eeeeee' => '#ffff66',
+% '#ffffff' => '#ffffb8',
+% );
+%
% my $bgcolor = '';
% my $last_classnum = -1;
% my $skipheader = 0;
@@ -56,7 +60,7 @@
% ";notenum=$notenum",
% 'actionlabel' => emt('Edit customer note'),
% 'width' => 616,
-% 'height' => 538, #575
+% 'height' => 575,
% 'frame' => 'top',
% );
% my $clickjs = qq!onclick="$onclick"!;
@@ -103,21 +107,23 @@
% $last_classnum = $note->classnum;
% }
+% my $color = $note->sticky ? $sticky_color{$bgcolor} : $bgcolor;
+
<TR>
- <% note_datestr($note,$conf,$bgcolor) %>
- <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ <% note_datestr($note,$conf,$color) %>
+ <TD CLASS="grid" BGCOLOR="<% $color %>">
&nbsp;<% $note->usernum ? $note->access_user->name : $note->otaker %>
</TD>
% if ($conf->exists('note-classes') && $conf->config('note-classes') == 1) {
- <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ <TD CLASS="grid" BGCOLOR="<% $color %>">
<% $note->classname %>
</TD>
% }
- <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
+ <TD CLASS="grid" BGCOLOR="<% $color %>">
<% $note->comments | defang %>
</TD>
% if($edit) {
- <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $edit %></TD>
+ <TD CLASS="grid" BGCOLOR="<% $color %>"><% $edit %></TD>
% }
</TR>
diff --git a/httemplate/view/cust_main/payment_history/voided_invoice.html b/httemplate/view/cust_main/payment_history/voided_invoice.html
index f9ff3079a..ba51b3bca 100644
--- a/httemplate/view/cust_main/payment_history/voided_invoice.html
+++ b/httemplate/view/cust_main/payment_history/voided_invoice.html
@@ -1,5 +1,5 @@
<DEL><% $link %><% $invoice %><% $link ? '</A>' : '' %></DEL>
-<I><% mt("voided [_1]", time2str($date_format, $cust_bill_void->void_date) ) |h %>
+<I><% mt("voided ([_1]) [_2]", $cust_bill_void->reason, time2str($date_format, $cust_bill_void->void_date) ) |h %>
% my $void_user = $cust_bill_void->void_access_user;
% if ($void_user) {
by <% $void_user->username %></I>
diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html
index a8194a75f..207ab9cdd 100644
--- a/httemplate/view/cust_main/payment_history/voided_payment.html
+++ b/httemplate/view/cust_main/payment_history/voided_payment.html
@@ -1,5 +1,5 @@
<DEL><% mt("Payment [_1] by [_2]", $info, $cust_pay_void->otaker ) |h %></DEL>
-<I><% mt("voided [_1]", time2str($date_format, $cust_pay_void->void_date) ) |h %>
+<I><% mt("voided ([_1]) [_2]", $cust_pay_void->reason, time2str($date_format, $cust_pay_void->void_date) ) |h %>
% my $void_user = $cust_pay_void->void_access_user;
% if ($void_user) {
by <% $void_user->username %></I>