summaryrefslogtreecommitdiff
path: root/httemplate
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate')
-rw-r--r--httemplate/browse/deploy_zone.html2
-rw-r--r--httemplate/browse/log_email.html92
-rwxr-xr-xhttemplate/browse/part_pkg.cgi8
-rw-r--r--httemplate/edit/cust_pkg_detail.html3
-rwxr-xr-xhttemplate/edit/cust_pkg_discount.html66
-rw-r--r--httemplate/edit/elements/rate_detail.html8
-rw-r--r--httemplate/edit/log_email.html45
-rw-r--r--httemplate/edit/msg_template/email.html6
-rw-r--r--httemplate/edit/process/cust_pkg_discount.html96
-rw-r--r--httemplate/edit/process/elements/process.html2
-rw-r--r--httemplate/edit/process/log_email.html18
-rw-r--r--httemplate/edit/process/quick-cust_pkg.cgi29
-rw-r--r--httemplate/edit/process/quotation_pkg_detail.html45
-rw-r--r--httemplate/edit/process/rate_detail.html16
-rw-r--r--httemplate/edit/quotation_pkg_detail.html116
-rw-r--r--httemplate/edit/rate.cgi10
-rw-r--r--httemplate/elements/menu.html4
-rw-r--r--httemplate/elements/popup_link.html4
-rw-r--r--httemplate/elements/select-months.html11
-rw-r--r--httemplate/elements/tr-select-months.html16
-rw-r--r--httemplate/elements/tr-select-msg_template.html12
-rw-r--r--httemplate/elements/tr-select-pkg-discount.html196
-rw-r--r--httemplate/images/Actions-document-edit-icon.pngbin0 -> 733 bytes
-rw-r--r--httemplate/misc/delete-log_email.html20
-rw-r--r--httemplate/misc/order_pkg.html17
-rw-r--r--httemplate/search/cust_bill_pkg.cgi28
-rw-r--r--httemplate/search/cust_bill_pkg_discount.html11
-rw-r--r--httemplate/search/cust_credit_bill_pkg.html51
-rw-r--r--httemplate/search/cust_pkg_discount.html9
-rw-r--r--httemplate/search/log.html4
-rwxr-xr-xhttemplate/search/report_tax-xls.cgi94
-rw-r--r--httemplate/search/report_tax.cgi96
-rwxr-xr-xhttemplate/view/cust_main/packages.html1
-rw-r--r--httemplate/view/cust_main/packages/package.html31
-rw-r--r--httemplate/view/cust_main/packages/status.html31
-rwxr-xr-xhttemplate/view/quotation.html18
36 files changed, 1045 insertions, 171 deletions
diff --git a/httemplate/browse/deploy_zone.html b/httemplate/browse/deploy_zone.html
index 02ebb8b8c..a1bd57f15 100644
--- a/httemplate/browse/deploy_zone.html
+++ b/httemplate/browse/deploy_zone.html
@@ -57,7 +57,7 @@
'(cir_speed_down, cir_speed_up)',
],
links => [ $link_fixed, $link_fixed, ],
- align => 'cllllrr',
+ align => 'cllllrrr',
nohtmlheader => 1,
disable_maxselect => 1,
disable_total => 1,
diff --git a/httemplate/browse/log_email.html b/httemplate/browse/log_email.html
new file mode 100644
index 000000000..0f64dd454
--- /dev/null
+++ b/httemplate/browse/log_email.html
@@ -0,0 +1,92 @@
+<% include('/elements/init_overlib.html') %>
+<% include('/browse/elements/browse.html',
+ 'title' => 'Log email condition configuration',
+ 'name_singular' => 'condition',
+ 'html_init' => '<P STYLE="margin-top: 0">'
+ . $add_condition_link
+ . ' | '
+ . $system_log_link
+ . '</P>'
+ . '<SCRIPT>'
+ . $areyousure
+ . '</SCRIPT>',
+ 'query' => $query,
+ 'count_query' => $count_query,
+ 'header' => [ '#',
+ 'Context',
+ 'Min. Level',
+ 'Template',
+ 'To',
+ '',
+ ],
+ 'fields' => [ 'logemailnum',
+ sub { $_[0]->context || '(all)' },
+ sub { $FS::Log::LEVELS[$_[0]->min_level] },
+ 'msgname',
+ 'to_addr',
+ $actions,
+ ],
+ 'sort_fields' => [ 'logemailnum',
+ 'context',
+ 'min_level',
+ 'msgname',
+ 'to_addr',
+ '',
+ ],
+ 'links' => [ $editlink,
+ $editlink,
+ $editlink,
+ $editlink,
+ $editlink,
+ '',
+ ],
+
+ ) %>
+
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+ unless $curuser->access_right([ 'View system logs', 'Configuration' ]);
+
+my $add_condition_link = include('/elements/popup_link.html',
+ 'action' => $p.'edit/log_email.html?popup=1',
+ 'label' => 'Add log email condition',
+ 'actionlabel' => 'Add log email condition',
+);
+
+my $system_log_link = qq(<A HREF="${p}search/log.html">System Log</A>);
+
+my $query = {
+ 'table' => 'log_email',
+ 'select' => '*',
+ 'addl_from' => 'LEFT JOIN msg_template USING (msgnum)',
+ 'hashref' => { },
+};
+
+my $count_query = "SELECT COUNT(*) FROM log_email";
+
+my $actions = sub {
+ my $log_email = shift;
+ my $logemailnum = $log_email->logemailnum;
+ qq!<A HREF="javascript:areyousure_delete_log_email($logemailnum)">(delete)</A>!;
+};
+
+my $areyousure_onclick = include('/elements/popup_link_onclick.html',
+ 'js_action' => q(') . $p . q(misc/delete-log_email.html?logemailnum=' + logemailnum),
+ 'actionlabel' => 'Delete log email condition',
+);
+
+my $areyousure = <<EOF;
+function areyousure_delete_log_email(logemailnum) {
+ if (confirm('Are you sure you want to delete log email condition #'+logemailnum+'?')) {
+${areyousure_onclick}
+ }
+}
+EOF
+
+my $editlink = [ $p.'edit/log_email.html?logemailnum=', 'logemailnum' ];
+
+</%init>
+
diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi
index 07f104e55..1e8b51030 100755
--- a/httemplate/browse/part_pkg.cgi
+++ b/httemplate/browse/part_pkg.cgi
@@ -88,6 +88,14 @@ if ( $cgi->param('missing_recur_fee') ) {
)";
}
+if ( $cgi->param('ratenum') =~ /^(\d+)$/ ) {
+ push @where, "EXISTS( SELECT 1 FROM part_pkg_option
+ WHERE optionname LIKE '%ratenum'
+ AND optionvalue = '$1'
+ AND part_pkg_option.pkgpart = part_pkg.pkgpart
+ )";
+}
+
if ( $cgi->param('family') =~ /^(\d+)$/ ) {
$family_pkgpart = $1;
push @where, "family_pkgpart = $1";
diff --git a/httemplate/edit/cust_pkg_detail.html b/httemplate/edit/cust_pkg_detail.html
index 5e107066d..b1e60dad5 100644
--- a/httemplate/edit/cust_pkg_detail.html
+++ b/httemplate/edit/cust_pkg_detail.html
@@ -46,7 +46,7 @@
<TR>
<TD></TD>
<TD>
- <INPUT TYPE="text" NAME="detail<% $row %>" SIZE="60" MAXLENGTH="65" VALUE="<% $_->detail |h %>" rownum="<% $row++ %>" onkeyup = "possiblyAddRow;" >
+ <INPUT TYPE="text" NAME="detail<% $row %>" SIZE="60" MAXLENGTH="65" VALUE="<% $_->detail |h %>" rownum="<% $row++ %>" onkeyup="possiblyAddRow" onchange="possiblyAddRow" >
</TD>
</TR>
@@ -88,6 +88,7 @@
detail_input.setAttribute('maxLength', 65);
detail_input.setAttribute('rownum', rownum);
detail_input.onkeyup = possiblyAddRow;
+ detail_input.onchange = possiblyAddRow;
detail_cell.appendChild(detail_input);
row.appendChild(detail_cell);
diff --git a/httemplate/edit/cust_pkg_discount.html b/httemplate/edit/cust_pkg_discount.html
index 0bb84b8f2..e1e3daede 100755
--- a/httemplate/edit/cust_pkg_discount.html
+++ b/httemplate/edit/cust_pkg_discount.html
@@ -1,18 +1,5 @@
-<% include('/elements/header-popup.html', "Discount Package") %>
-
-<SCRIPT TYPE="text/javascript">
-
- function enable_discount_pkg () {
- if ( document.DiscountPkgForm.discountnum.selectedIndex > 0 ) {
- document.DiscountPkgForm.submit.disabled = false;
- } else {
- document.DiscountPkgForm.submit.disabled = true;
- }
- }
-
-</SCRIPT>
-
-<% include('/elements/error.html') %>
+<& /elements/header-popup.html, "Discount Package" &>
+<& /elements/error.html &>
<FORM NAME="DiscountPkgForm" ACTION="<% $p %>edit/process/cust_pkg_discount.html" METHOD=POST>
<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
@@ -26,17 +13,17 @@
</TD>
</TR>
-<% include('/elements/tr-select-discount.html',
- 'empty_label' => ( $pkgdiscountnum ? '' : 'Select discount' ),
- 'onchange' => 'enable_discount_pkg()',
- 'cgi' => $cgi,
- )
-%>
-
+<& /elements/tr-select-pkg-discount.html,
+ curr_value_setup => $setup_discountnum,
+ curr_value_recur => $recur_discountnum,
+ disable_setup => $disable_setup,
+ disable_recur => $disable_recur,
+&>
+
</TABLE>
<BR>
-<INPUT NAME="submit" TYPE="submit" VALUE="Discount package" <% $pkgdiscountnum ? '' : 'DISABLED' %>>
+<INPUT NAME="submit" TYPE="submit" VALUE="Discount package">
</FORM>
</BODY>
@@ -44,14 +31,13 @@
<%init>
-#some false laziness w/misc/change_pkg.cgi
-
my $conf = new FS::Conf;
my $curuser = $FS::CurrentUser::CurrentUser;
die "access denied"
- unless $curuser->access_right('Discount customer package');
+ unless $curuser->access_right([ 'Discount customer package',
+ 'Waive setup fee']);
my $pkgnum = scalar($cgi->param('pkgnum'));
$pkgnum =~ /^(\d+)$/ or die "illegal pkgnum $pkgnum";
@@ -67,10 +53,30 @@ my $cust_pkg =
'extra_sql' => ' AND '. $curuser->agentnums_sql,
}) or die "unknown pkgnum $pkgnum";
-#my $cust_main = $cust_pkg->cust_main
-# or die "can't get cust_main record for custnum ". $cust_pkg->custnum.
-# " ( pkgnum ". cust_pkg->pkgnum. ")";
-
my $part_pkg = $cust_pkg->part_pkg;
+my @discounts = $cust_pkg->cust_pkg_discount_active;
+my ($setup_discountnum, $recur_discountnum);
+foreach (@discounts) {
+ if ( $_->setuprecur eq 'setup') {
+ die "multiple setup discounts on pkg#$pkgnum" if $setup_discountnum;
+ $setup_discountnum = $_->discountnum;
+ } elsif ( $_->setuprecur eq 'recur' ) {
+ die "multiple setup discounts on pkg#$pkgnum" if $recur_discountnum;
+ $recur_discountnum = $_->discountnum;
+ }
+}
+if ( $cust_pkg->waive_setup ) {
+ $setup_discountnum = -2;
+}
+
+my $disable_setup = 1;
+if ( !$cust_pkg->get('setup') and $cust_pkg->base_setup > 0 ) {
+ $disable_setup = 0;
+}
+my $disable_recur = 1;
+if ( $cust_pkg->base_recur > 0 ) {
+ $disable_recur = 0;
+}
+
</%init>
diff --git a/httemplate/edit/elements/rate_detail.html b/httemplate/edit/elements/rate_detail.html
index 7b5ec314a..32dd502ce 100644
--- a/httemplate/edit/elements/rate_detail.html
+++ b/httemplate/edit/elements/rate_detail.html
@@ -61,18 +61,18 @@ with row headers showing the region name and prefixes.
% $row++;
% }# foreach @rate_region
% if ( !$opt{regionnum} ) {
-%# global default
+% # global default for this cdrtypenum
<TR>
<TD COLSPAN=2 STYLE="padding-top: 10px">
<B>Global default</B> (for calls not matching any prefix)
</TD>
<TD STYLE="padding-top: 10px">
-% # default rate: set a null region
+% # default rate: set a null region for this cdr type
<B>
<& .detail_box,
- detail => $rate->default_detail,
+ detail => $rate->default_detail($cdrtypenum),
ratetimenum => '',
- cdrtypenum => '',
+ cdrtypenum => $cdrtypenum,
regionnum => '',
ratenum => $rate->ratenum
&>
diff --git a/httemplate/edit/log_email.html b/httemplate/edit/log_email.html
new file mode 100644
index 000000000..bbce7c708
--- /dev/null
+++ b/httemplate/edit/log_email.html
@@ -0,0 +1,45 @@
+<% include( 'elements/edit.html',
+ 'name_singular' => 'log email condition',
+ 'table' => 'log_email',
+ 'fields' => [
+ { 'field' => 'context',
+ 'type' => 'select',
+ 'options' => [ '', @contexts ],
+ 'labels' => { '' => '(all)', map { $_ => $_ } @contexts },
+ 'curr_value' => scalar($cgi->param('context')),
+ },
+ { 'field' => 'min_level',
+ 'type' => 'select',
+ 'options' => [ 0..7 ],
+ 'labels' => { map {$_ => $FS::Log::LEVELS[$_]} 0..7 },
+ 'curr_value' => scalar($cgi->param('min_level')),
+ },
+ 'to_addr',
+ { 'field' => 'msgnum',
+ 'type' => 'select-msg_template',
+ 'empty_label' => 'Select template',
+ 'required' => 1,
+ },
+ ],
+ 'labels' => {
+ 'context' => 'Context',
+ 'min_level' => 'Min. Level',
+ 'to_addr' => 'To',
+ 'msgnum' => 'Message',
+ },
+ 'viewall_dir' => 'browse',
+ 'popup' => $opts{'popup'},
+ 'form_init' => $opts{'popup'} ? q(<INPUT TYPE="hidden" NAME="popup" VALUE="1">) : '',
+ )
+%>
+<%once>
+my @contexts = sort FS::log_context->contexts;
+</%once>
+<%init>
+
+my %opts = @_;
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right([ 'View system logs', 'Configuration' ]);
+
+</%init>
diff --git a/httemplate/edit/msg_template/email.html b/httemplate/edit/msg_template/email.html
index dc70ef6ec..b0c1aa31a 100644
--- a/httemplate/edit/msg_template/email.html
+++ b/httemplate/edit/msg_template/email.html
@@ -302,6 +302,11 @@ my %substitutions = (
'$payinfo' => 'Card/account# (masked)',
'$error' => 'Decline reason',
],
+ 'system_log' => [
+ '$logmessage' => 'Log entry message',
+ '$loglevel' => 'Log entry level',
+ '$logcontext' => 'Log entry context',
+ ],
);
tie my %sections, 'Tie::IxHash', (
@@ -315,6 +320,7 @@ tie my %sections, 'Tie::IxHash', (
'svc_domain'=> 'Domain service fields',
'svc_phone' => 'Phone service fields',
'svc_broadband' => 'Broadband service fields',
+'system_log' => 'System log fields',
);
my $widget = new HTML::Widgets::SelectLayers(
diff --git a/httemplate/edit/process/cust_pkg_discount.html b/httemplate/edit/process/cust_pkg_discount.html
index 4a71f6975..143611ef9 100644
--- a/httemplate/edit/process/cust_pkg_discount.html
+++ b/httemplate/edit/process/cust_pkg_discount.html
@@ -14,9 +14,8 @@
<%init>
my $curuser = $FS::CurrentUser::CurrentUser;
-
-die "access denied"
- unless $curuser->access_right('Discount customer package');
+my $can_discount = $curuser->access_right('Discount customer package');
+my $can_waive_setup = $curuser->access_right('Waive setup fee');
#this search is really for security wrt agent virt...
#maybe move it to the cust_pkg_discount->insert call?
@@ -29,20 +28,81 @@ my $cust_pkg = qsearchs({
});
die 'unknown pkgnum' unless $cust_pkg;
-my $cust_pkg_discount = new FS::cust_pkg_discount {
- 'pkgnum' => $cust_pkg->pkgnum,
- 'discountnum' => scalar($cgi->param('discountnum')),
- 'months_used' => 0,
- 'end_date' => '', #XXX
- #for the create a new discount case
- '_type' => scalar($cgi->param('discountnum__type')),
- 'amount' => scalar($cgi->param('discountnum_amount')),
- 'percent' => scalar($cgi->param('discountnum_percent')),
- 'months' => scalar($cgi->param('discountnum_months')),
- 'setup' => scalar($cgi->param('discountnum_setup')),
- #'linked' => scalar($cgi->param('discountnum_linked')),
- #'disabled' => $self->discountnum_disabled,
-};
-my $error = $cust_pkg_discount->insert;
+my $error;
+my %discountnum = (setup => '', recur => '');
+if ( $cgi->param('setup_discountnum') == -2 ) {
+
+ die "access denied" unless $can_waive_setup; # UI protects against this
+ # waive setup fee (not really a discount but treated as one in the UI)
+ if ( !$cust_pkg->get('setup') and !$cust_pkg->waive_setup ) {
+ $cust_pkg->set('waive_setup' => 'Y');
+ $error = $cust_pkg->replace;
+ }
+
+} else {
+ if ( $cgi->param('setup_discountnum') =~ /^(-?\d+)$/ ) {
+ $discountnum{setup} = $1;
+ }
+ if ( $cust_pkg->waive_setup ) {
+ $cust_pkg->set('waive_setup', '');
+ $error = $cust_pkg->replace;
+ }
+}
+
+if ( $cgi->param('recur_discountnum') =~ /^(-?\d+)$/ ) {
+
+ $discountnum{recur} = $1;
+
+}
+
+my @active_discounts = $cust_pkg->cust_pkg_discount_active;
+
+foreach my $setuprecur (qw(setup recur)) {
+
+ if ( $cust_pkg->get('setup') and $setuprecur eq 'setup' ) {
+ # no point allowing setup discounts to be edited for a previously setup
+ # package
+ next;
+ }
+
+ my ($active) = grep { $_->setuprecur eq $setuprecur } @active_discounts;
+
+ if ( $active ) {
+ if ( $active->discount ne $discountnum{$setuprecur} ) {
+ $active->set('disabled' => 'Y');
+ $error ||= $active->replace;
+ undef $active;
+ } else {
+ # it's the same discountnum; don't touch it
+ next;
+ }
+ }
+
+ if ( $discountnum{$setuprecur} ) {
+ die "access_denied" unless $can_discount;
+ my $cust_pkg_discount = FS::cust_pkg_discount->new({
+ 'pkgnum' => $cust_pkg->pkgnum,
+ 'discountnum' => $discountnum{$setuprecur},
+ 'setuprecur' => $setuprecur,
+ 'months_used' => 0,
+ 'end_date' => '', #XXX
+ #for the create a new discount case
+ '_type' => scalar($cgi->param($setuprecur.'_discountnum__type')),
+ 'amount' => scalar($cgi->param($setuprecur.'_discountnum_amount')),
+ 'percent' => scalar($cgi->param($setuprecur.'_discountnum_percent')),
+ });
+ if ( $setuprecur eq 'setup' ) {
+ $cust_pkg_discount->set('setup' => 'Y');
+ $cust_pkg_discount->set('months' => 1);
+ } else {
+ if ( $cgi->param($setuprecur.'_discountnum_months') =~ /^(\w+)$/ ) {
+ $cust_pkg_discount->set('months' => $1);
+ }
+ }
+
+ $error ||= $cust_pkg_discount->insert;
+
+ }
+} # foreach $setuprecur
</%init>
diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html
index a76f4befb..fd12c61d9 100644
--- a/httemplate/edit/process/elements/process.html
+++ b/httemplate/edit/process/elements/process.html
@@ -164,7 +164,9 @@ process();
% # some false laziness with the above
% my ($form_name, $job_fields) = @{ $opt{'progress_init'} };
<form name="<% $form_name %>">
+ <input type="hidden" name="<% $pkey %>" value="<% $new->get($pkey) %>">
% foreach my $field (@$job_fields) {
+% next if $field eq $pkey;
<input type="hidden" name="<% $field %>" value="<% $cgi->param($field) |h %>">
% }
<& /elements/progress-init.html,
diff --git a/httemplate/edit/process/log_email.html b/httemplate/edit/process/log_email.html
new file mode 100644
index 000000000..769e180a8
--- /dev/null
+++ b/httemplate/edit/process/log_email.html
@@ -0,0 +1,18 @@
+<% include('elements/process.html',
+ 'table' => 'log_email',
+ %processopts
+ ) %>
+<%init>
+
+my %opts = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+ unless $curuser->access_right([ 'View system logs', 'Configuration' ]);
+
+my %processopts = $opts{'popup'}
+ ? ( 'popup_reload' => 'Logging email added' )
+ : ( 'redirect' => $fsurl.'browse/log_email.html?' ); # id will be needlessly appended, should be harmless
+
+</%init>
diff --git a/httemplate/edit/process/quick-cust_pkg.cgi b/httemplate/edit/process/quick-cust_pkg.cgi
index f1d8c2696..60352154a 100644
--- a/httemplate/edit/process/quick-cust_pkg.cgi
+++ b/httemplate/edit/process/quick-cust_pkg.cgi
@@ -79,9 +79,6 @@ my $contactnum = $1;
$cgi->param('locationnum') =~ /^(\-?\d*)$/
or die 'illegal locationnum '. $cgi->param('locationnum');
my $locationnum = $1;
-$cgi->param('discountnum') =~ /^(\-?\d*)$/
- or die 'illegal discountnum '. $cgi->param('discountnum');
-my $discountnum = $1;
# for going right to a provision service after ordering a package
my( $svcpart, $part_svc ) = ( '', '' );
@@ -114,19 +111,29 @@ my %hash = (
'refnum' => $refnum,
'contactnum' => $contactnum,
'locationnum' => $locationnum,
- 'discountnum' => $discountnum,
- #for the create a new discount case
- 'discountnum__type' => scalar($cgi->param('discountnum__type')),
- 'discountnum_amount' => scalar($cgi->param('discountnum_amount')),
- 'discountnum_percent' => scalar($cgi->param('discountnum_percent')),
- 'discountnum_months' => scalar($cgi->param('discountnum_months')),
- 'discountnum_setup' => scalar($cgi->param('discountnum_setup')),
'contract_end' => ( scalar($cgi->param('contract_end'))
? parse_datetime($cgi->param('contract_end'))
: ''
),
- 'waive_setup' => ( $cgi->param('waive_setup') eq 'Y' ? 'Y' : '' ),
);
+
+if ( $cgi->param('setup_discountnum') =~ /^(-?\d+)$/ ) {
+ if ( $1 == -2 ) {
+ $hash{waive_setup} = 'Y';
+ } else {
+ $hash{setup_discountnum} = $1;
+ $hash{setup_discountnum_amount} = $cgi->param('setup_discountnum_amount');
+ $hash{setup_discountnum_percent} = $cgi->param('setup_discountnum_percent');
+ }
+}
+
+if ( $cgi->param('recur_discountnum') =~ /^(-?\d+)$/ ) {
+ $hash{recur_discountnum} = $1;
+ $hash{recur_discountnum_amount} = $cgi->param('recur_discountnum_amount');
+ $hash{recur_discountnum_percent} = $cgi->param('recur_discountnum_percent');
+ $hash{recur_discountnum_months} = $cgi->param('recur_discountnum_months');
+}
+
$hash{'custnum'} = $cust_main->custnum if $cust_main;
if ( $cgi->param('start') eq 'on_hold' ) {
diff --git a/httemplate/edit/process/quotation_pkg_detail.html b/httemplate/edit/process/quotation_pkg_detail.html
new file mode 100644
index 000000000..2fc420280
--- /dev/null
+++ b/httemplate/edit/process/quotation_pkg_detail.html
@@ -0,0 +1,45 @@
+% if ( $error ) {
+<% header('Error') %>
+<FONT COLOR="#ff0000"><B><% $error |h %></B></FONT><BR><BR>
+<CENTER><INPUT TYPE="BUTTON" VALUE="OK" onClick="parent.cClick()"></CENTER>
+</BODY></HTML>
+% } else {
+<% header($action) %>
+ <SCRIPT TYPE="text/javascript">
+ window.top.location.reload();
+ </SCRIPT>
+ </BODY></HTML>
+% }
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+ unless $curuser->access_right('Generate quotation');
+
+$cgi->param('pkgnum') =~ /^(\d+)$/ or die 'illegal pkgnum';
+my $pkgnum = $1;
+
+my $quotation_pkg = qsearchs({
+ 'table' => 'quotation_pkg',
+ 'addl_from' => 'LEFT JOIN quotation USING ( quotationnum )'.
+ 'LEFT JOIN cust_main USING ( custnum )',
+ 'hashref' => { 'quotationpkgnum' => $pkgnum },
+ 'extra_sql' => ' AND '. $curuser->agentnums_sql,
+});
+
+my @orig_details = $quotation_pkg->details();
+
+my $action = 'Quotation details'.
+ ( scalar(@orig_details) ? ' changed ' : ' added ' );
+
+my $param = $cgi->Vars;
+my @details = ();
+for ( my $row = 0; exists($param->{"detail$row"}); $row++ ) {
+ push @details, $param->{"detail$row"}
+ if $param->{"detail$row"} =~ /\S/;
+}
+
+my $error = $quotation_pkg->set_details(@details);
+
+</%init>
diff --git a/httemplate/edit/process/rate_detail.html b/httemplate/edit/process/rate_detail.html
index f8a744418..4020ce9e2 100644
--- a/httemplate/edit/process/rate_detail.html
+++ b/httemplate/edit/process/rate_detail.html
@@ -2,7 +2,7 @@
'table' => 'rate_detail',
'popup_reload' => 'Rate changed', #a popup "parent reload" for now
#someday change the individual element and go away instead
- 'noerror_callback' => $set_default_detail
+ #'noerror_callback' => $set_default_detail
&>
<%init>
@@ -12,19 +12,11 @@ die "access denied"
my $set_default_detail = sub {
my ($cgi, $rate_detail) = @_;
- if (!$rate_detail->dest_regionnum) {
+ if (!$rate_detail->dest_regionnum and !$rate_detail->cdrtypenum) {
# then this is a global default rate
+ # default_detailnum is no longer used, but maintain it anyway (and point
+ # it at the one with null cdrtypenum)
my $rate = $rate_detail->rate;
- if ($rate->default_detailnum) {
- if ($rate->default_detailnum == $rate_detail->ratedetailnum) {
- return;
- } else {
- # there's somehow an existing default rate. remove it.
- my $old_default = $rate->default_detail;
- my $error = $old_default->delete;
- die "$error (removing old default rate)\n" if $error;
- }
- }
$rate->set('default_detailnum' => $rate_detail->ratedetailnum);
my $error = $rate->replace;
die "$error (setting default rate)\n" if $error;
diff --git a/httemplate/edit/quotation_pkg_detail.html b/httemplate/edit/quotation_pkg_detail.html
new file mode 100644
index 000000000..b8f589a9a
--- /dev/null
+++ b/httemplate/edit/quotation_pkg_detail.html
@@ -0,0 +1,116 @@
+<% include("/elements/header-popup.html", $title, '',
+ ( $cgi->param('error') ? '' : 'onload="addRow()"' ),
+ )
+%>
+
+%# <% include('/elements/error.html') %>
+
+<FORM ACTION="process/quotation_pkg_detail.html" NAME="DetailForm" ID="DetailForm" METHOD="POST">
+
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
+
+<TABLE ID="DetailTable" BGCOLOR="#cccccc" BORDER=0 CELLSPACING=1 STYLE="background-color: #cccccc">
+
+ <TR>
+ <TD ALIGN="right">Package</TD>
+ <TD BGCOLOR="#ffffff"><% $part_pkg->pkg %></TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Comment</TD>
+ <TD BGCOLOR="#ffffff"><% $part_pkg->comment |h %></TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2>Detail: </TD>
+ </TR>
+
+% my $row = 0;
+% for ( @details ) {
+
+ <TR>
+ <TD></TD>
+ <TD>
+ <INPUT TYPE="text" NAME="detail<% $row %>" SIZE="60" MAXLENGTH="65" VALUE="<% $_ |h %>" rownum="<% $row++ %>" onkeyup="possiblyAddRow" onchange="possiblyAddrow">
+ </TD>
+ </TR>
+
+% }
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" ID="submit" NAME="submit" VALUE="<% $title %>">
+
+</FORM>
+
+<SCRIPT TYPE="text/javascript">
+% # abject false laziness with edit/cust_pkg_detail.html
+
+ var rownum = <% $row %>;
+
+ function possiblyAddRow() {
+ if ( ( rownum - this.getAttribute('rownum') ) == 1 ) {
+ addRow();
+ }
+ }
+
+ function addRow() {
+
+ var table = document.getElementById('DetailTable');
+ var tablebody = table.getElementsByTagName('tbody').item(0);
+
+ var row = document.createElement('TR');
+
+ var empty_cell = document.createElement('TD');
+ row.appendChild(empty_cell);
+
+ var detail_cell = document.createElement('TD');
+
+ var detail_input = document.createElement('INPUT');
+ detail_input.setAttribute('name', 'detail'+rownum);
+ detail_input.setAttribute('id', 'detail'+rownum);
+ detail_input.setAttribute('size', 60);
+ detail_input.setAttribute('maxLength', 65);
+ detail_input.setAttribute('rownum', rownum);
+ detail_input.onkeyup = possiblyAddRow;
+ detail_input.onchange = possiblyAddRow;
+ detail_cell.appendChild(detail_input);
+
+ row.appendChild(detail_cell);
+
+ tablebody.appendChild(row);
+
+ rownum++;
+
+ }
+
+</SCRIPT>
+
+</BODY>
+</HTML>
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+ unless $curuser->access_right('Generate quotation');
+
+$cgi->param('pkgnum') =~ /^(\d+)$/ or die 'illegal pkgnum';
+my $pkgnum = $1;
+
+my $quotation_pkg = qsearchs({
+ 'table' => 'quotation_pkg',
+ 'addl_from' => 'LEFT JOIN quotation USING ( quotationnum )'.
+ 'LEFT JOIN cust_main USING ( custnum )',
+ 'hashref' => { 'quotationpkgnum' => $pkgnum },
+ 'extra_sql' => ' AND '. $curuser->agentnums_sql,
+});
+
+my $part_pkg = $quotation_pkg->part_pkg;
+
+my @details = $quotation_pkg->details;
+
+my $title = ( scalar(@details) ? 'Edit ' : 'Add ' ). 'Quotation Details';
+
+</%init>
diff --git a/httemplate/edit/rate.cgi b/httemplate/edit/rate.cgi
index 1b052d62d..5bfc108c1 100644
--- a/httemplate/edit/rate.cgi
+++ b/httemplate/edit/rate.cgi
@@ -1,7 +1,11 @@
-<% include("/elements/header.html","$action Rate plan", menubar(
+<& /elements/header.html,
+ "$action Rate plan",
+ menubar(
'View all rate plans' => "${p}browse/rate.cgi",
- ))
-%>
+ 'View packages that use this plan' => "${p}browse/part_pkg.cgi?ratenum="
+ . $rate->ratenum,
+ )
+&>
<% include('/elements/progress-init.html',
'OneTrueForm',
diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html
index ea6933198..dcc02c2b1 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -787,6 +787,10 @@ $config_misc{'Inventory classes and inventory'} = [ $fsurl.'browse/inventory_cla
$config_misc{'Upload targets'} = [ $fsurl.'browse/upload_target.html', 'Billing and payment upload destinations' ]
if $curuser->access_right('Configuration');
+$config_misc{'System log emails'} = [ $fsurl.'browse/log_email.html', 'Configure conditions for sending email when logging' ]
+ if $curuser->access_right('View system logs')
+ || $curuser->access_right('Configuration');
+
tie my %config_menu, 'Tie::IxHash';
if ( $curuser->access_right('Configuration' ) ) {
%config_menu = (
diff --git a/httemplate/elements/popup_link.html b/httemplate/elements/popup_link.html
index 2b6b187e9..e9728ac1c 100644
--- a/httemplate/elements/popup_link.html
+++ b/httemplate/elements/popup_link.html
@@ -18,11 +18,13 @@ Example:
'height' => 336,
'color' => '#ff0000',
'closetext' => 'Go Away', # the value '' removes the link
+ 'title' => 'Hover Text',
#uncommon opt
'aname' => "target", # link NAME= value, useful for #targets
'target' => '_parent',
'style' => 'css-attribute:value',
+ 'html_label' => '<IMG SRC="something.png">', # overrides label
}
&>
@@ -30,6 +32,7 @@ Example:
% if ($params->{'action'} && $label) {
<A HREF="javascript:void(0);"
onClick="<% $onclick |n %>"
+ <% $params->{'title'} ? 'TITLE="' . $params->{'title'}. '"' : '' |n %>
<% $params->{'aname'} ? 'NAME="'. $params->{'aname'}. '"' : '' |n %>
<% $params->{'target'} ? 'TARGET="'. $params->{'target'}. '"' : '' |n %>
<% $params->{'style'} ? 'STYLE="'. $params->{'style'}. '"' : '' |n %>
@@ -48,6 +51,7 @@ if (ref($_[0]) eq 'HASH') {
my $label = $params->{'label'};
$label =~ s/ /&nbsp;/g;
+$label = $params->{'html_label'} || $label;
my $onclick = include('/elements/popup_link_onclick.html', $params);
</%init>
diff --git a/httemplate/elements/select-months.html b/httemplate/elements/select-months.html
new file mode 100644
index 000000000..1cd72fcba
--- /dev/null
+++ b/httemplate/elements/select-months.html
@@ -0,0 +1,11 @@
+<%init>
+my %opt = @_;
+$opt{id} ||= $opt{field}; # should be the default everywhere
+my $max = $opt{max} || 36;
+$opt{options} = [ '', 1 .. $max ];
+$opt{labels} = { '' => '',
+ map { $_ => emt('[quant,_1,month]', $_) } 1 .. $max
+ };
+
+</%init>
+<& select.html, %opt &>
diff --git a/httemplate/elements/tr-select-months.html b/httemplate/elements/tr-select-months.html
index b90ce1ed7..4d8576411 100644
--- a/httemplate/elements/tr-select-months.html
+++ b/httemplate/elements/tr-select-months.html
@@ -1,11 +1,5 @@
-<%init>
-my %opt = @_;
-$opt{id} ||= $opt{field}; # should be the default everywhere
-my $max = $opt{max} || 36;
-$opt{options} = [ '', 1 .. $max ];
-$opt{labels} = { '' => '',
- map { $_ => emt('[quant,_1,month]', $_) } 1 .. $max
- };
-
-</%init>
-<& tr-select.html, %opt &>
+<& tr-td-label.html, @_ &>
+ <td>
+ <& select-months.html, @_ &>
+ </td>
+</tr>
diff --git a/httemplate/elements/tr-select-msg_template.html b/httemplate/elements/tr-select-msg_template.html
new file mode 100644
index 000000000..1f899e01c
--- /dev/null
+++ b/httemplate/elements/tr-select-msg_template.html
@@ -0,0 +1,12 @@
+<% include('/elements/tr-td-label.html',
+ 'label' => $opt{'label'} || 'Message template: ',
+ 'required' => $opt{'required'} ) %>
+ <TD><% include('select-msg_template.html', %opt) %></TD>
+</TR>
+
+<%init>
+
+my %opt = @_;
+
+</%init>
+
diff --git a/httemplate/elements/tr-select-pkg-discount.html b/httemplate/elements/tr-select-pkg-discount.html
new file mode 100644
index 000000000..dc38cff3e
--- /dev/null
+++ b/httemplate/elements/tr-select-pkg-discount.html
@@ -0,0 +1,196 @@
+<%doc>
+
+In order_pkg.html or similar:
+
+<& /elements/tr-select-pkg-discount.html,
+ curr_value_setup => ($cgi->param('setup_discountnum') || ''),
+ curr_value_recur => ($cgi->param('recur_discountnum') || ''),
+ disable_setup => 0,
+ disable_recur => 0,
+&>
+
+This provides the following:
+- If the user can waive setup fees or apply a discount, they get a
+ select box for the setup discount, with "Waive setup fee" as an option.
+- If they can custom discount, they will also get "Custom discount" as an
+ option. If selected, this will show fields to enter the custom discount
+ amount/percentage.
+- If they can waive setup fees but NOT apply a discount, they only get a
+ checkbox to waive setup fee.
+- Same for recurring fee, but without the "waive setup fee" stuff, obviously.
+- Custom recurring discounts also have an option for a duration in months.
+
+"disable_setup" locks the setup discount, but will still show a static
+description if curr_value_setup is set. Likewise "disable_recur".
+
+</%doc>
+% # SETUP DISCOUNT
+
+% # select-discount knows about the "custom discount" ACL
+% if ( $curuser->access_right('Discount customer package')
+% and !$opt{disable_setup} )
+% {
+% my $pre_options = [ '' => '(none)' ];
+% if ( $curuser->access_right('Waive setup fee') ) {
+% push @$pre_options, -2 => 'Waive setup fee';
+% }
+<& tr-td-label.html, label => emt('Setup fee') &>
+ <td>
+ <& select-discount.html,
+ field => 'setup_discountnum',
+ id => 'setup_discountnum',
+ hashref => { disabled => '',
+ setup => 'Y'
+ },
+ extra_sql => ' AND (percent > 0 OR months = 1)',
+ curr_value => $opt{'curr_value_setup'},
+ disable_empty => 1,
+ pre_options => $pre_options,
+ &>
+ </td>
+</tr>
+% # custom discount
+<tr class="setup_discount_custom">
+ <td></td>
+ <td>Amount <% $money_char %>
+ <& input-text.html,
+ field => 'setup_discountnum_amount',
+ curr_value => ($cgi->param('setup_discountnum_amount') || ''),
+ size => 5,
+ &>
+ or percentage
+ <& input-text.html,
+ field => 'setup_discountnum_percent',
+ curr_value => ($cgi->param('setup_discountnum_percent') || ''),
+ size => 5,
+ &> %
+ </td>
+</tr>
+
+% } elsif ( $curuser->access_right('Waive setup fee')
+% and !$opt{disable_setup} )
+% {
+
+<& tr-td-label.html, label => emt('Waive setup fee') &>
+ <td>
+ <& checkbox.html,
+ field => 'setup_discountnum',
+ id => 'setup_discountnum',
+ value => '-2',
+ curr_value => $opt{'curr_value_setup'},
+ &>
+ </td>
+</tr>
+
+% } elsif ( $opt{'curr_value_setup'} ) { # user can't do anything
+%
+% my $discount = FS::discount->by_key($opt{'curr_value_setup'});
+
+ <INPUT TYPE="hidden" NAME="setup_discountnum" VALUE="<% $opt{curr_value_setup} %>">
+
+ <% $discount->description_short %>
+
+% }
+
+% # RECUR DISCOUNT
+
+% if ( $curuser->access_right('Discount customer package')
+% and !$opt{disable_recur} ) {
+
+<& tr-td-label.html, label => emt('Recurring fee') &>
+ <td>
+ <& select-discount.html,
+ field => 'recur_discountnum',
+ id => 'recur_discountnum',
+ hashref => { disabled => '' },
+ curr_value => $opt{'curr_value_recur'},
+ &>
+
+ </td>
+</tr>
+% # custom discount
+<tr class="recur_discount_custom">
+ <td></td>
+ <td>Amount <% $money_char %>
+ <& input-text.html,
+ field => 'recur_discountnum_amount',
+ curr_value => ($cgi->param('recur_discountnum_amount') || ''),
+ size => 5,
+ &>
+ or percentage
+ <& input-text.html,
+ field => 'recur_discountnum_percent',
+ curr_value => ($cgi->param('recur_discountnum_percent') || ''),
+ size => 5,
+ &> %
+ </td>
+</tr>
+<tr class="recur_discount_custom">
+ <td></td>
+ <td>Expires after
+ <& /elements/select-months.html,
+ field => 'recur_discountnum_months',
+ curr_value => ($cgi->param('recur_discountnum_months') || ''),
+ &>
+ </td>
+</tr>
+
+% } elsif ( $opt{'curr_value_recur'} ) {
+%
+% my $discount = FS::discount->by_key($opt{'curr_value_recur'});
+
+ <INPUT TYPE="hidden" NAME="recur_discountnum" VALUE="<% $opt{curr_value_recur} %>">
+
+ <% $discount->description %>
+
+% }
+
+<SCRIPT TYPE="text/javascript">
+$(document).ready(function() {
+ ['setup', 'recur'].forEach(function(x) {
+ var discountnum = $('#'+x+'_discountnum');
+
+ // if it's been set to a custom discount, show custom discount inputs
+ var discountnum_changed = function() {
+ var val = this.value;
+ var custom = $('.'+x+'_discount_custom');
+ if ( val == -1 ) {
+ custom.show();
+ } else {
+ custom.hide();
+ }
+ };
+
+ discountnum.on('change', discountnum_changed);
+ discountnum.trigger('change');
+
+ // if amount contains a value, disable percent, and vice versa
+ var amount_percent_keyup = function(event) {
+ var other = event.data;
+ if (this.value.length > 0) {
+ other.disabled = true;
+ } else {
+ other.disabled = false;
+ }
+ };
+ var amount = $('#'+x+'_discountnum_amount');
+ var percent = $('#'+x+'_discountnum_percent');
+ amount.on('keyup', percent, amount_percent_keyup);
+ percent.on('keyup', amount, amount_percent_keyup);
+
+ amount.trigger('keyup');
+ percent.trigger('keyup');
+ });
+});
+</script>
+<%init>
+
+my %opt = (
+ 'curr_value_setup' => ($cgi->param('setup_discountnum') || ''),
+ 'curr_value_recur' => ($cgi->param('recur_discountnum') || ''),
+ @_
+);
+my $curuser = $FS::CurrentUser::CurrentUser;
+my $money_char = FS::Conf->new->config('money_char') || '$';
+
+</%init>
diff --git a/httemplate/images/Actions-document-edit-icon.png b/httemplate/images/Actions-document-edit-icon.png
new file mode 100644
index 000000000..8bfc32943
--- /dev/null
+++ b/httemplate/images/Actions-document-edit-icon.png
Binary files differ
diff --git a/httemplate/misc/delete-log_email.html b/httemplate/misc/delete-log_email.html
new file mode 100644
index 000000000..cc17b15a0
--- /dev/null
+++ b/httemplate/misc/delete-log_email.html
@@ -0,0 +1,20 @@
+% if ($error) {
+<P STYLE="color: red"><% $error %></P>
+% } else {
+<H1>Log email condition deleted</H1>
+<SCRIPT>
+window.top.location.reload();
+</SCRIPT>
+% }
+
+<%init>
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right([ 'View system logs', 'Configuration' ]);
+
+my $logemailnum = $cgi->param('logemailnum');
+$logemailnum =~ /^\d+$/ or die "bad logemailnum '$logemailnum'";
+my $log_email = FS::log_email->by_key($logemailnum)
+ or die "logemailnum '$logemailnum' not found";
+my $error = $log_email->delete;
+</%init>
+
diff --git a/httemplate/misc/order_pkg.html b/httemplate/misc/order_pkg.html
index cb2bd4832..e28250110 100644
--- a/httemplate/misc/order_pkg.html
+++ b/httemplate/misc/order_pkg.html
@@ -127,22 +127,7 @@
% if ( $discount_cust_pkg || $waive_setup_fee ) {
<FONT CLASS="fsinnerbox-title"><% mt('Discounting') |h %></FONT>
<% ntable("#cccccc") %>
-
-% if ( $waive_setup_fee ) {
- <TR>
- <TH ALIGN="right"><% mt('Waive setup fee') |h %> </TH>
- <TD COLSPAN=6><INPUT TYPE="checkbox" NAME="waive_setup" VALUE="Y"></TD>
- </TR>
-% }
-
-% if ( $discount_cust_pkg ) {
- <& /elements/tr-select-discount.html,
- 'element_etc' => 'DISABLED',
- 'colspan' => 7,
- 'cgi' => $cgi,
- &>
-% }
-
+ <& /elements/tr-select-pkg-discount.html &>
</TABLE><BR>
% }
diff --git a/httemplate/search/cust_bill_pkg.cgi b/httemplate/search/cust_bill_pkg.cgi
index 278382feb..ab5aad776 100644
--- a/httemplate/search/cust_bill_pkg.cgi
+++ b/httemplate/search/cust_bill_pkg.cgi
@@ -705,9 +705,19 @@ my $pay_sub = "SELECT SUM(cust_bill_pay_pkg.amount)
";
push @select, "($pay_sub) AS pay_amount";
-#total credits
-my $credit_sub = 'SELECT SUM(amount) AS credit_amount, billpkgnum
- FROM cust_credit_bill_pkg GROUP BY billpkgnum';
+# showing credited amount, optionally with date filtering
+my $credit_where = '';
+if ( $cgi->param('credit_begin') or $cgi->param('credit_end') ) {
+ my($cr_begin, $cr_end) = FS::UI::Web::parse_beginning_ending($cgi, 'credit');
+ $credit_where = "WHERE cust_credit_bill._date >= $cr_begin " .
+ "AND cust_credit_bill._date <= $cr_end";
+}
+
+my $credit_sub = "SELECT SUM(cust_credit_bill_pkg.amount) AS credit_amount, billpkgnum
+ FROM cust_credit_bill_pkg
+ JOIN cust_credit_bill USING (creditbillnum)
+ $credit_where
+ GROUP BY billpkgnum";
$join_pkg .= " LEFT JOIN ($credit_sub) AS item_credit
ON (cust_bill_pkg.billpkgnum = item_credit.billpkgnum)";
@@ -737,6 +747,10 @@ if ( $cgi->param('salesnum') =~ /^(\d+)$/ ) {
$cgi->param('classnum', 0) unless $cgi->param('classnum');
}
+#credit flag (include only those that have credit(s) applied)
+if ( $cgi->param('credit') ) {
+ push @where, 'credit_amount > 0';
+}
my $where = join(' AND ', @where);
$where &&= "WHERE $where";
@@ -775,7 +789,13 @@ my $ilink = [ "${p}view/cust_bill.cgi?", 'invnum' ];
my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
my $pay_link = ''; #[, 'billpkgnum', ];
-my $credit_link = [ "${p}search/cust_credit_bill_pkg.html?billpkgnum=", 'billpkgnum', ];
+my $credit_param = '';
+foreach ('credit_begin', 'credit_end') {
+ if ( $cgi->param($_) ) {
+ $credit_param .= "$_=" . $cgi->param($_) . ';';
+ }
+}
+my $credit_link = [ "${p}search/cust_credit_bill_pkg.html?${credit_param}billpkgnum=", 'billpkgnum', ];
warn "\n\nQUERY:\n".Dumper($query)."\n\nCOUNT_QUERY:\n$count_query\n\n"
if $cgi->param('debug');
diff --git a/httemplate/search/cust_bill_pkg_discount.html b/httemplate/search/cust_bill_pkg_discount.html
index 6da5787a0..c63482827 100644
--- a/httemplate/search/cust_bill_pkg_discount.html
+++ b/httemplate/search/cust_bill_pkg_discount.html
@@ -20,9 +20,7 @@
sub { $_[0]->cust_pkg_discount->discount->description },
sub { $_[0]->cust_pkg_discount->discount->classname },
sub { sprintf($money_char.'%.2f', shift->amount ) },
- sub { my $m = shift->months;
- $m =~ /\./ ? sprintf('%.2f', $m) : $m;
- },
+ $months_sub,
'pkg',#sub { $_[0]->cust_bill_pkg->cust_pkg->part_pkg->pkg },
'invnum',
sub { time2str('%b %d %Y', shift->_date ) },
@@ -218,4 +216,11 @@ my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
my $conf = new FS::Conf;
my $money_char = $conf->config('money_char') || '$';
+my $months_sub = sub {
+ my $cust_bill_pkg_discount = shift;
+ return 'Setup'
+ if $cust_bill_pkg_discount->cust_pkg_discount->setuprecur eq 'setup';
+ sprintf('%.2f', $cust_bill_pkg_discount->months);
+};
+
</%init>
diff --git a/httemplate/search/cust_credit_bill_pkg.html b/httemplate/search/cust_credit_bill_pkg.html
index b5a0ee9f6..5facd4ab3 100644
--- a/httemplate/search/cust_credit_bill_pkg.html
+++ b/httemplate/search/cust_credit_bill_pkg.html
@@ -3,11 +3,12 @@
'name_singular' => 'credit application',
'query' => $query,
'count_query' => $count_query,
- 'count_addl' => [ $money_char. '%.2f total', ],
+ 'count_addl' => \@count_addl,
'header' => [
#'#',
'Amount',
+ 'Tax exempt',
#credit
'Date',
@@ -26,7 +27,9 @@
],
'fields' => [
#'creditbillpkgnum',
- sub { sprintf($money_char.'%.2f', shift->amount ) },
+ sub { sprintf($money_char.'%.2f', shift->amount ) },
+
+ sub { sprintf($money_char.'%.2f', shift->get('exempt_credited') ) },
sub { time2str('%b %d %Y', shift->get('cust_credit_date') ) },
sub { shift->cust_credit_bill->cust_credit->otaker },
@@ -44,6 +47,7 @@
],
'sort_fields' => [
'amount',
+ 'exempt_credited',
'cust_credit_date',
'', #'otaker',
'', #reason
@@ -61,6 +65,7 @@
'',
'',
'',
+ '',
@post_desc_null,
$ilink,
$ilink,
@@ -68,11 +73,12 @@
FS::UI::Web::cust_header()
),
],
- 'align' => 'rrllll'.
+ 'align' => 'rrrllll'.
$post_desc_align.
'rr'.
FS::UI::Web::cust_aligns(),
- 'color' => [
+ 'color' => [
+ '',
'',
'',
'',
@@ -91,6 +97,7 @@
'',
'',
'',
+ '',
@post_desc_null,
'',
'',
@@ -286,7 +293,6 @@ if ( $cgi->param('out') ) {
#}
push @where, $loc_sql;
-warn $loc_sql;
}
my($title, $name);
@@ -369,7 +375,7 @@ if ( $cgi->param('report_group') =~ /^(=|!=) (.*)$/ && $cgi->param('istax') ) {
}
-push @where, 'cust_bill_pkg.pkgnum != 0' if $cgi->param('nottax');
+push @where, '(cust_bill_pkg.pkgnum != 0 OR cust_bill_pkg.feepart is not null)' if $cgi->param('nottax');
push @where, 'cust_bill_pkg.pkgnum = 0' if $cgi->param('istax');
if ( $cgi->param('cust_tax') ) {
@@ -393,6 +399,9 @@ if ( $cgi->param('cust_tax') ) {
my $count_query = "SELECT COUNT(DISTINCT creditbillpkgnum),
SUM(cust_credit_bill_pkg.amount)";
+if ( $cgi->param('nottax') ) {
+ $count_query .= ", SUM(exempt_credited)";
+}
my $join_cust =
' JOIN cust_bill ON ( cust_bill_pkg.invnum = cust_bill.invnum )'.
@@ -405,6 +414,21 @@ my $join_cust_bill_pkg = 'LEFT JOIN cust_bill_pkg USING ( billpkgnum )';
if ( $cgi->param('nottax') ) {
+ # There can be multiple cust_tax_exempt_pkg records with the same
+ # creditbillpkgnum iff the line item is exempt from multiple taxes.
+ # They will all have the same amount, except in the case where there are
+ # different exemption types and so the exemption amounts are different.
+ # In that case, show the amount of the largest exemption.
+
+ $join_cust_bill_pkg .= '
+ LEFT JOIN(
+ SELECT creditbillpkgnum,
+ MAX(0 - cust_tax_exempt_pkg.amount) AS exempt_credited
+ FROM cust_tax_exempt_pkg
+ WHERE creditbillpkgnum IS NOT NULL
+ GROUP BY creditbillpkgnum
+ ) AS exempt_credit USING (creditbillpkgnum)
+ ';
$join_pkg = ' LEFT JOIN cust_pkg USING ( pkgnum )
LEFT JOIN part_pkg USING ( pkgpart )
LEFT JOIN part_pkg AS override
@@ -472,6 +496,12 @@ push @select, 'part_pkg.pkg' unless $cgi->param('istax');
push @select, 'cust_main.custnum',
FS::UI::Web::cust_sql_fields();
+if ( $cgi->param('istax') ) {
+ push @select, 'NULL AS exempt_credited'; # just display zero
+} elsif ( $cgi->param('nottax') ) {
+ push @select, 'exempt_credited';
+}
+
my @post_desc_header = ();
my @post_desc = ();
my @post_desc_null = ();
@@ -555,4 +585,13 @@ my $location_sub = sub {
};
+my @count_addl = ( $money_char. '%.2f total', );
+if ( $cgi->param('nottax') ) {
+ push @count_addl, ( $money_char. '%.2f tax exempt' );
+}
+
+if ( $cgi->param('debug') ) {
+ warn "\nQUERY:\n" . Dumper($query) . "\nCOUNT_QUERY:\n$count_query\n\n";
+}
+
</%init>
diff --git a/httemplate/search/cust_pkg_discount.html b/httemplate/search/cust_pkg_discount.html
index f0c7447a5..ab6ad2bd0 100644
--- a/httemplate/search/cust_pkg_discount.html
+++ b/httemplate/search/cust_pkg_discount.html
@@ -18,9 +18,7 @@
sub { ucfirst( shift->status ) },
sub { shift->discount->description },
sub { shift->discount->classname },
- sub { my $m = shift->months_used;
- $m =~ /\./ ? sprintf('%.2f',$m) : $m;
- },
+ $months_used_sub,
'otaker',
'pkg',
\&FS::UI::Web::cust_fields,
@@ -165,4 +163,9 @@ my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
my $conf = new FS::Conf;
+my $months_used_sub = sub {
+ my $cust_pkg_discount = shift;
+ return 'Setup only' if $cust_pkg_discount->setuprecur eq 'setup';
+ return sprintf('%.2f', $cust_pkg_discount->months_used);
+};
</%init>
diff --git a/httemplate/search/log.html b/httemplate/search/log.html
index d1bfb6cc9..a707928d7 100644
--- a/httemplate/search/log.html
+++ b/httemplate/search/log.html
@@ -1,6 +1,7 @@
<& elements/search.html,
'title' => 'System Log',
'name_singular' => 'event',
+ 'menubar' => \@menubar,
'html_init' => include('.head'),
'query' => $query,
'count_query' => $count_query,
@@ -204,6 +205,9 @@ my $curuser = $FS::CurrentUser::CurrentUser;
die "access denied"
unless $curuser->access_right([ 'View system logs', 'Configuration' ]);
+my @menubar = ();
+push @menubar, qq(<A HREF="${fsurl}browse/log_email.html" STYLE="text-decoration: underline;">Configure conditions for sending email when logging</A>),
+
$cgi->param('min_level', 0) unless defined($cgi->param('min_level'));
$cgi->param('max_level', 7) unless defined($cgi->param('max_level'));
diff --git a/httemplate/search/report_tax-xls.cgi b/httemplate/search/report_tax-xls.cgi
index 743f14788..773b403f1 100755
--- a/httemplate/search/report_tax-xls.cgi
+++ b/httemplate/search/report_tax-xls.cgi
@@ -122,7 +122,7 @@ my %default = (
border => 1,
);
my @widths = ( #ick
- 30, (13) x 5, 3, 7.5, 3, 11, 11, 3, 11, 3, 11
+ 30, (13) x 6, 3, 7.5, 3, 11, 11, 3, 11, 3, 11
);
my @format = ( {}, {}, {} ); # white row, gray row, yellow (totals) row
@@ -134,29 +134,34 @@ foreach (keys(%formatdef)) {
italic => 1,
%f);
}
-my $ws = $workbook->add_worksheet('taxreport');
+my $ws = $workbook->add_worksheet('Sales and Tax');
# main title
$ws->merge_range(0, 0, 0, 14, $report->title, $format[0]->{title});
+$ws->set_row(0, 30);
# excel position
my $x = 0;
my $y = 2;
my $colhead = $format[0]->{colhead};
# print header
-$ws->merge_range($y, 1, $y, 5, 'Sales', $colhead);
-$ws->merge_range($y, 6, $y+1, 8, 'Rate', $colhead);
-$ws->merge_range($y, 9, $y, 15, 'Tax', $colhead);
+$ws->merge_range($y, 1, $y, 6, 'Sales', $colhead);
+$ws->merge_range($y, 7, $y+1, 9, 'Rate', $colhead);
+$ws->merge_range($y, 10, $y, 16, 'Tax', $colhead);
$y++;
$colhead = $format[0]->{colhead_small};
-$ws->write($y, 1, [ 'Total', 'Exempt customer', 'Exempt package', 'Monthly exemption',
+$ws->write($y, 1, [ 'Total',
+ 'Exempt customer',
+ 'Exempt package',
+ 'Monthly exemption',
+ 'Credited',
'Taxable' ], $colhead);
-$ws->write($y, 9, 'Estimated', $colhead);
-$ws->write($y, 10, 'Invoiced', $colhead);
-$ws->write($y, 12, 'Credited', $colhead);
-$ws->write($y, 14, 'Net due', $colhead);
-$ws->write($y, 15, 'Collected',$colhead);
+$ws->write($y, 10, 'Estimated', $colhead);
+$ws->write($y, 11, 'Invoiced', $colhead);
+$ws->write($y, 13, 'Credited', $colhead);
+$ws->write($y, 15, 'Net due', $colhead);
+$ws->write($y, 16, 'Collected',$colhead);
$y++;
# print data
@@ -168,7 +173,7 @@ foreach my $row (@rows) {
if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) {
$rownum = 1;
if ( $params{breakdown}->{pkgclass} ) {
- $ws->merge_range($y, 0, $y, 14,
+ $ws->merge_range($y, 0, $y, 15,
$pkgclass_name{$row->{pkgclass}},
$format[0]->{sectionhead}
);
@@ -182,7 +187,7 @@ foreach my $row (@rows) {
}
$ws->write($y, $x, $row->{label}, $f->{rowhead});
$x++;
- foreach (qw(sales exempt_cust exempt_pkg exempt_monthly taxable)) {
+ foreach (qw(sales exempt_cust exempt_pkg exempt_monthly sales_credited taxable)) {
$ws->write($y, $x, $row->{$_} || 0, $f->{currency});
$x++;
}
@@ -229,6 +234,69 @@ for my $x (0..scalar(@widths)-1) {
$ws->set_column($x, $x, $widths[$x]);
}
+# do the same for the credit worksheet
+$ws = $workbook->add_worksheet('Credits');
+
+my $title = $report->title;
+$title =~ s/Tax Report/Credits/;
+# main title
+$ws->merge_range(0, 0, 0, 14, $title, $format[0]->{title});
+$ws->set_row(0, 30); # height
+# excel position
+$x = 0;
+$y = 2;
+
+$colhead = $format[0]->{colhead};
+# print header
+$ws->merge_range($y, 1, $y+1, 1, 'Total', $colhead);
+$ws->merge_range($y, 2, $y, 4, 'Applied to', $colhead);
+
+$y++;
+$colhead = $format[0]->{colhead_small};
+$ws->write($y, 2, [ 'Taxable sales',
+ 'Tax-exempt sales',
+ 'Taxes'
+ ], $colhead);
+$y++;
+
+# print data
+$rownum = 1;
+$prev_row = { pkgclass => 'DUMMY PKGCLASS' };
+
+foreach my $row (@rows) {
+ $x = 0;
+ if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) {
+ $rownum = 1;
+ if ( $params{breakdown}->{pkgclass} ) {
+ $ws->merge_range($y, 0, $y, 4,
+ $pkgclass_name{$row->{pkgclass}},
+ $format[0]->{sectionhead}
+ );
+ $y++;
+ }
+ }
+ # pick a format set
+ my $f = $format[$rownum % 2];
+ if ( $row->{total} ) {
+ $f = $format[2];
+ }
+ $ws->write($y, $x, $row->{label}, $f->{rowhead});
+ $x++;
+ foreach (qw(credits sales_credited exempt_credited tax_credited)) {
+ $ws->write($y, $x, $row->{$_} || 0, $f->{currency});
+ $x++;
+ }
+
+ $rownum++;
+ $y++;
+ $prev_row = $row;
+}
+
+for my $x (0..4) {
+ $ws->set_column($x, $x, $widths[$x]);
+}
+
+
$workbook->close;
http_header('Content-Length' => length($data));
diff --git a/httemplate/search/report_tax.cgi b/httemplate/search/report_tax.cgi
index 0ad143f01..9e625c80f 100644
--- a/httemplate/search/report_tax.cgi
+++ b/httemplate/search/report_tax.cgi
@@ -18,6 +18,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px }
.bigmath { font-size: large; font-weight: bold; font: sans-serif; text-align: center }
.total { font-style: italic }
</STYLE>
+
<& /elements/table-grid.html &>
<THEAD>
<TR>
@@ -77,18 +78,18 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px }
% # cust_bill_pkg.cgi wants a list of specific taxnums (and package class)
% # cust_credit_bill_pkg.html wants a geographic scope (and package class)
% my $rowlink = ';taxnum=' . $row->{taxnums};
-% my $rowregion = ';country=' . $cgi->param('country');
-% foreach my $loc (qw(state county city district)) {
-% if ( $row->{$loc} ) {
-% $rowregion .= ";$loc=" . uri_escape($row->{$loc});
-% }
-% }
+% # DON'T EVER USE THIS
+% # my $rowregion = ';country=' . $cgi->param('country');
+% # foreach my $loc (qw(state county city district)) {
+% # if ( $row->{$loc} ) {
+% # $rowregion .= ";$loc=" . uri_escape($row->{$loc});
+% # }
+% # }
% # and also the package class, if we're limiting package class
% if ( $params{breakdown}->{pkgclass} ) {
% $rowlink .= ';classnum=' . ($row->{pkgclass} || 0);
-% $rowregion .= ';classnum=' . ($row->{pkgclass} || 0);
+% # $rowregion .= ';classnum=' . ($row->{pkgclass} || 0);
% }
-%warn $rowregion;
%
% if ( $row->{total} ) {
</TBODY><TBODY CLASS="total">
@@ -122,7 +123,7 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px }
</TD>
% # credited sales
<TD>
- <A HREF="<% $salescreditlink . $rowregion %>">
+ <A HREF="<% $salescreditlink . $rowlink %>">
<% $money_sprintf->( $row->{sales_credited} ) %>
</A>
</TD>
@@ -183,6 +184,80 @@ TD.rowhead { font-weight: bold; text-align: left; padding: 0px 3px }
% }
</TABLE>
+<BR>
+<& /elements/table-grid.html &>
+ <THEAD>
+ <TR>
+ <TH ROwSPAN=2></TH>
+ <TH ROWSPAN=2>Total credits</TH>
+ <TH COLSPAN=3>Applied to</TH>
+ </TR>
+ <TR STYLE="font-size: small">
+ <TH>Taxable sales</TH>
+ <TH>Tax-exempt sales</TH>
+ <TH>Taxes</TH>
+ </TR>
+ </THEAD>
+
+% $rownum = 0;
+% $prev_row = { pkgclass => 'DUMMY PKGCLASS' };
+
+ <TBODY>
+% # mostly duplicates the stuff above...
+% # but putting it all in one giant table is no good
+% foreach my $row (@rows) {
+% if ( $row->{pkgclass} ne $prev_row->{pkgclass} ) {
+% if ( $rownum > 0 ) { # start a new section
+% $rownum = 0;
+ </TBODY><TBODY>
+% }
+% if ( $params{breakdown}->{pkgclass} ) { # and caption the new section
+ <TR>
+ <TD COLSPAN=5 CLASS="sectionhead">
+ <% $pkgclass_name{$row->{pkgclass}} %>
+ </TD>
+ </TR>
+% }
+% } # if $row->{pkgclass} ne ...
+
+% my $rowlink = ';taxnum=' . $row->{taxnums};
+%
+% if ( $row->{total} ) {
+ </TBODY><TBODY CLASS="total">
+% }
+ <TR CLASS="row<% $rownum % 2 %>">
+ <TD CLASS="rowhead"><% $row->{label} |h %></TD>
+ <TD>
+% # Total credits
+ <% $money_sprintf->( $row->{credits} ) %>
+ </TD>
+% # Credits to taxable sales
+ <TD>
+ <A HREF="<% $salescreditlink . $rowlink %>">
+ <% $money_sprintf->( $row->{sales_credited} ) %>
+ </A>
+ </TD>
+% # ... to exempt sales (link is the same, it shows both exempt and taxable)
+ <TD>
+ <A HREF="<% $salescreditlink . $rowlink %>">
+ <% $money_sprintf->( $row->{exempt_credited} ) %>
+ </A>
+ </TD>
+% # ... to taxes
+ <TD>
+%# <A HREF="<% $creditlink . $rowlink %>"> currently broken
+ <% $money_sprintf->( $row->{tax_credited} ) %>
+%# </A>
+ </TD>
+ </TR>
+% $rownum++;
+% $prev_row = $row;
+% } # foreach my $row
+% # no "out of taxable region" for credits (yet)
+ </TBODY>
+</TABLE>
+
+
<& /elements/footer.html &>
<%init>
@@ -240,10 +315,11 @@ if ( $params{agentnum} ) {
my $saleslink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;nottax=1";
my $taxlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;istax=1";
my $exemptlink = $p. "search/cust_tax_exempt_pkg.cgi?$dateagentlink";
-my $salescreditlink = $p. "search/cust_credit_bill_pkg.html?$dateagentlink;nottax=1";
+my $salescreditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;nottax=1;credit=1";
if ( $params{'credit_date'} eq 'cust_credit_bill' ) {
$salescreditlink =~ s/begin/credit_begin/;
$salescreditlink =~ s/end/credit_end/;
+ $saleslink .= ";credit_begin=$beginning;credit_end=$ending";
}
#my $creditlink = $p. "search/cust_bill_pkg.cgi?$dateagentlink;credit=1;istax=1";
#if ( $params{'credit_date'} eq 'cust_credit_bill' ) {
diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html
index 4903e185b..0c67843d4 100755
--- a/httemplate/view/cust_main/packages.html
+++ b/httemplate/view/cust_main/packages.html
@@ -42,6 +42,7 @@ table.hiddenrows {
z-index: 1;
text-align: center;
}
+
</STYLE>
% # activate rolldown buttons for hidden package blocks
<SCRIPT TYPE="text/javascript">
diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html
index 8aa64039c..e98b95e1c 100644
--- a/httemplate/view/cust_main/packages/package.html
+++ b/httemplate/view/cust_main/packages/package.html
@@ -53,10 +53,7 @@
(&nbsp;<%onetime_change_link($cust_pkg)%>&nbsp;)
% }
% # also, you can discount it
-% if ( $curuser->access_right('Discount customer package')
-% && ! scalar($cust_pkg->cust_pkg_discount_active)
-% && ! scalar($cust_pkg->part_pkg->part_pkg_discount)
-% ) {
+% if ( $can_discount_pkg ) {
(&nbsp;<%pkg_discount_link($cust_pkg)%>&nbsp;)
% }
<BR>
@@ -79,14 +76,7 @@
(&nbsp;<%pkg_change_link($cust_pkg)%>&nbsp;)
% }
%
-% if ( $curuser->access_right('Discount customer package')
-% && $part_pkg->can_discount
-% && ! scalar( @{ $cust_pkg->{_cust_pkg_discount_active} } )
-% && ( ! $opt{'term_discounts'}
-% || ! scalar($cust_pkg->part_pkg->part_pkg_discount)
-% )
-% )
-% {
+% if ( $can_discount_pkg ) {
% $br=1;
(&nbsp;<%pkg_discount_link($cust_pkg)%>&nbsp;)
% }
@@ -437,4 +427,21 @@ sub pkg_event_link {
'</a>';
}
+# figure out if this user will be able to edit either the setup or recurring
+# discounts for this package
+my $can_discount_pkg = (
+ $part_pkg->can_discount
+ and
+ ( ( $curuser->access_right(['Discount customer package', 'Waive setup fee'])
+ and $cust_pkg->base_setup > 0
+ and !$cust_pkg->setup
+ )
+ or
+ ( $curuser->access_right('Discount customer package')
+ and $cust_pkg->base_recur > 0
+ and $cust_pkg->freq ne '0'
+ )
+ )
+);
+
</%init>
diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html
index 7e125f72e..13bd2024b 100644
--- a/httemplate/view/cust_main/packages/status.html
+++ b/httemplate/view/cust_main/packages/status.html
@@ -461,10 +461,11 @@ sub pkg_status_row_changed {
my $part_pkg = $old->part_pkg;
$html .= pkg_status_row_colspan(
$cust_pkg,
- emt("Changed from [_1]: [_2]",
- $cust_pkg->change_pkgnum,
- $part_pkg->pkg_comment(cust_pkg=>$old, nopartpkg=>1)
- ),
+# emt("Changed from [_1]: [_2]",
+# $cust_pkg->change_pkgnum,
+# $part_pkg->pkg_comment(cust_pkg=>$old, nopartpkg=>1)
+# ),
+ '',
'',
'size' => '-1',
'align' => 'right',
@@ -529,17 +530,25 @@ sub pkg_status_row_discount {
my $discount = $cust_pkg_discount->discount;
- my $label = '<B>'.emt('Discount').'</B>: '. $discount->description;
- if ( $discount->months ) {
+ my $label = '<SPAN STYLE="font-size: small"><B>';
+ if ( $cust_pkg_discount->setuprecur eq 'setup' ) {
+ $label .= emt('Setup Discount');
+ } else {
+ $label .= emt('Recurring Discount');
+ }
+ $label .= '</B>: '. $discount->description;
+ warn Dumper $cust_pkg_discount;
+ if ( $discount->months > 0 and $cust_pkg_discount->months_used > 0 ) {
my $remaining = $discount->months - $cust_pkg_discount->months_used;
$remaining = sprintf('%.2f', $remaining) if $remaining =~ /\./;
- $label .= emt("([_1] months remaining)",$remaining);
+ $label .= <br> . emt("([_1] months remaining)",$remaining);
}
+ $label .= '</SPAN>';
- $label .= ' <FONT SIZE="-1">('.
- '<A HREF="../misc/delete-cust_pkg_discount.html?'.
- $cust_pkg_discount->pkgdiscountnum.
- '">'.emt('remove discount').'</A>)</FONT>';
+ #$label .= ' <FONT SIZE="-1">('.
+ # '<A HREF="../misc/delete-cust_pkg_discount.html?'.
+ # $cust_pkg_discount->pkgdiscountnum.
+ # '">'.emt('remove discount').'</A>)</FONT>';
$html .= pkg_status_row_colspan( $cust_pkg, $label, '', %opt );
diff --git a/httemplate/view/quotation.html b/httemplate/view/quotation.html
index 67609a1c6..18625095e 100755
--- a/httemplate/view/quotation.html
+++ b/httemplate/view/quotation.html
@@ -91,6 +91,8 @@ my $curuser = $FS::CurrentUser::CurrentUser;
#die "access denied"
# unless $curuser->access_right('View quotations');
+my $can_generate_quotation = $curuser->access_right('Generate quotation');
+
my $quotationnum;
my($query) = $cgi->keywords;
if ( $query =~ /^(\d+)$/ ) {
@@ -119,11 +121,23 @@ my $link = "quotationnum=$quotationnum";
#$link .= ';notice_name='. $notice_name if $notice_name;
my $preref_callback = sub {
- areyousure_link("${p}misc/delete-quotation_pkg.html?". shift->quotationpkgnum,
+ my $quotation_pkg = shift;
+ $can_generate_quotation ?
+ areyousure_link("${p}misc/delete-quotation_pkg.html?". $quotation_pkg->quotationpkgnum,
emt('Are you sure you want to remove this package from the quotation?'),
emt('Remove this package'), #tooltip
qq(<img src="${p}images/cross.png">), #link
- );
+ ) .
+ include('/elements/popup_link.html',
+ action => "${p}edit/quotation_pkg_detail.html?pkgnum=" .
+ $quotation_pkg->quotationpkgnum,
+ html_label => qq(<IMG SRC="${p}images/Actions-document-edit-icon.png">),
+ title => emt('Edit quotation details'),
+ actionlabel => emt('Edit quotation details'),
+ color => '#333399',
+ width => 763,
+ )
+ : '';
};
sub areyousure_link {