summaryrefslogtreecommitdiff
path: root/httemplate
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2015-07-13 17:26:48 -0700
committerMark Wells <mark@freeside.biz>2015-07-14 13:25:05 -0700
commit98f6d91ec7eaa907204afbfeb90ede1e3bff656d (patch)
treee5d7b870c4965f9a2b580e3cad5aed82d300e5c8 /httemplate
parent57e3a0e08b81d52851314c60f37115a05b9be79e (diff)
automatic package changes for supplemental packages, #37102
Diffstat (limited to 'httemplate')
-rwxr-xr-xhttemplate/browse/part_pkg.cgi72
-rwxr-xr-xhttemplate/edit/part_pkg.cgi47
-rw-r--r--httemplate/elements/freeside.css12
-rw-r--r--httemplate/elements/select.html26
-rw-r--r--httemplate/elements/tr-select-expire_months.html10
-rw-r--r--httemplate/elements/tr-select-months.html12
-rwxr-xr-xhttemplate/view/cust_main/packages.html26
-rw-r--r--httemplate/view/cust_main/packages/package.html24
-rwxr-xr-xhttemplate/view/cust_main/packages/section.html8
-rw-r--r--httemplate/view/cust_main/packages/status.html57
10 files changed, 223 insertions, 71 deletions
diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi
index f8de620a7..c2f1430d7 100755
--- a/httemplate/browse/part_pkg.cgi
+++ b/httemplate/browse/part_pkg.cgi
@@ -247,6 +247,7 @@ push @fields, sub {
$part_pkg->part_pkg_discount;
[
+ # Line 0: Family package link (if applicable)
( !$family_pkgpart &&
$part_pkg->pkgpart == $part_pkg->family_pkgpart ? () : [
{
@@ -257,13 +258,13 @@ push @fields, sub {
'link' => $p.'browse/part_pkg.cgi?family='.$part_pkg->family_pkgpart,
}
] ),
- [
+ [ # Line 1: Plan type (Anniversary, Prorate, Call Rating, etc.)
{ data =>$plan,
align=>'center',
colspan=>2,
},
],
- [
+ [ # Line 2: Setup fee
{ data =>$money_char.
sprintf('%.2f ', $part_pkg->option('setup_fee') ),
align=>'right'
@@ -278,7 +279,7 @@ push @fields, sub {
align=>'left',
},
],
- [
+ [ # Line 3: Recurring fee
{ data=>(
$is_recur
? $money_char. sprintf('%.2f', $part_pkg->option('recur_fee'))
@@ -288,20 +289,56 @@ push @fields, sub {
colspan=> ( $is_recur ? 1 : 2 ),
},
( $is_recur
- ? { data => ( $is_recur
- ? ' &nbsp; '. $part_pkg->freq_pretty.
- ( $part_pkg->option('recur_fee') == 0
- && $part_pkg->recur_show_zero
- ? ' (printed on invoices)'
- : ''
- )
- : '' ),
+ ? { data => ' &nbsp; '. $part_pkg->freq_pretty.
+ ( $part_pkg->option('recur_fee') == 0
+ && $part_pkg->recur_show_zero
+ ? ' (printed on invoices)'
+ : ''
+ ),
align=>'left',
}
: ()
),
],
- (
+ [ { data => '&nbsp;' }, ], # Line 4: empty
+ ( $part_pkg->adjourn_months ?
+ [ # Line 5: Adjourn months
+ { data => mt('After [quant,_1,month], <strong>suspend</strong> the package.',
+ $part_pkg->adjourn_months),
+ align => 'left',
+ size => -1,
+ colspan => 2,
+ }
+ ] : ()
+ ),
+ ( $part_pkg->contract_end_months ?
+ [ # Line 6: Contract end months
+ { data => mt('After [quant,_1,month], <strong>contract ends</strong>.',
+ $part_pkg->contract_end_months),
+ align => 'left',
+ size => -1,
+ colspan => 2,
+ }
+ ] : ()
+ ),
+ ( $part_pkg->expire_months ?
+ [ # Line 7: Expire months and automatic transfer
+ { data => $part_pkg->change_to_pkgpart ?
+ mt('After [quant,_1,month], <strong>change to</strong> ',
+ $part_pkg->expire_months) .
+ qq(<a href="${p}edit/part_pkg.cgi?) .
+ $part_pkg->change_to_pkgpart .
+ qq(">) . $part_pkg->change_to_pkg->pkg . qq(</a>) . '.'
+ : mt('After [quant,_1,month], <strong>cancel</strong> the package.',
+ $part_pkg->expire_months)
+ ,
+ align => 'left',
+ size => -1,
+ colspan => 2,
+ }
+ ] : ()
+ ),
+ ( # Usage prices
map { my $amount = $_->amount / ($_->target_info->{multiplier} || 1);
my $label = $_->target_info->{label};
[
@@ -315,7 +352,8 @@ push @fields, sub {
}
$part_pkg->part_pkg_usageprice
),
- ( map { my $dst_pkg = $_->dst_pkg;
+ ( # Supplementals
+ map { my $dst_pkg = $_->dst_pkg;
[
{ data => 'Supplemental: &nbsp;'.
'<A HREF="#'. $dst_pkg->pkgpart . '">' .
@@ -327,7 +365,8 @@ push @fields, sub {
}
$part_pkg->supp_part_pkg_link
),
- ( map {
+ ( # Billing add-ons/bundle packages
+ map {
my $dst_pkg = $_->dst_pkg;
[
{ data => 'Add-on:&nbsp;'.$dst_pkg->pkg_comment,
@@ -338,7 +377,8 @@ push @fields, sub {
}
$part_pkg->bill_part_pkg_link
),
- ( scalar(@discounts)
+ ( # Discounts available
+ scalar(@discounts)
? [
{ data => '<b>Discounts</b>',
align=>'center', #?
@@ -360,7 +400,7 @@ push @fields, sub {
@discounts
: ()
),
- ];
+ ]; # end of "middle column"
# $plan_labels{$part_pkg->plan}.'<BR>'.
# $money_char.sprintf('%.2f setup<BR>', $part_pkg->option('setup_fee') ).
diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi
index a90a62508..9f5510d65 100755
--- a/httemplate/edit/part_pkg.cgi
+++ b/httemplate/edit/part_pkg.cgi
@@ -28,7 +28,7 @@
'onsubmit' => 'confirm_submit',
- 'labels' => {
+ 'labels' => {
'pkgpart' => 'Package Definition',
'pkg' => 'Package',
%locale_field_labels,
@@ -69,6 +69,10 @@
'supp_dst_pkgpart' => 'When ordering package, also order',
'report_option' => 'Report classes',
'delay_start' => 'Default delay (days)',
+ 'adjourn_months' => 'Suspend the package after ',
+ 'contract_end_months' => 'Contract ends after ',
+ 'expire_months' => 'Cancel the package after ',
+ 'change_to_pkgpart'=> 'and replace it with ',
},
'fields' => [
@@ -164,6 +168,37 @@
sort $conf->config('currencies')
),
+ ( $conf->exists('part_pkg-delay_start')
+ ? ( { type => 'tablebreak-tr-title',
+ value => 'Delayed start',
+ },
+ { field => 'delay_start',
+ type => 'text', size => 6 },
+ )
+ : ()
+ ),
+
+ { type => 'tablebreak-tr-title',
+ value => 'Limited duration',
+ },
+ { field => 'adjourn_months',
+ type => 'select-months',
+ },
+ { field => 'contract_end_months',
+ type => 'select-months',
+ },
+ { field => 'expire_months',
+ type => 'select-expire_months',
+ },
+ { field => 'change_to_pkgpart',
+ type => 'select-part_pkg',
+ extra_sql => sub { $pkgpart
+ ? "AND pkgpart != $pkgpart"
+ : ''
+ },
+ empty_label => 'no package',
+ },
+
#price plan
#setup fee
#recurring frequency
@@ -219,16 +254,6 @@
)
),
- ( $conf->exists('part_pkg-delay_start')
- ? ( { type => 'tablebreak-tr-title',
- value => 'Delayed start',
- },
- { field => 'delay_start',
- type => 'text', size => 6 },
- )
- : ()
- ),
-
{ type => 'columnnext' },
{type=>'justtitle', value=>'Agent (reseller) types' },
diff --git a/httemplate/elements/freeside.css b/httemplate/elements/freeside.css
index d4e155aa1..dbd27cbaa 100644
--- a/httemplate/elements/freeside.css
+++ b/httemplate/elements/freeside.css
@@ -323,3 +323,15 @@ div#overDiv {
box-shadow: #333333 1px 1px 2px;
}
+/* view/cust_main/packages/package.html */
+div.package-marker-supplemental {
+ height: 100%;
+ border-left: solid #bbbbff 30px;
+ display: inline-block;
+}
+
+div.package-marker-change_from {
+ height: 100%;
+ border-left: solid #bbffbb 30px;
+ display: inline-block;
+}
diff --git a/httemplate/elements/select.html b/httemplate/elements/select.html
index 4492681de..42cd89504 100644
--- a/httemplate/elements/select.html
+++ b/httemplate/elements/select.html
@@ -1,3 +1,29 @@
+<%doc>
+<& select.html,
+ # required
+ field => 'myfield', # NAME property
+ curr_value => 'foo',
+ labels => { # or 'option_labels'
+ 'AL' => 'Alabama',
+ 'AK' => 'Alaska',
+ 'AR' => 'Arkansas',
+ },
+ options => [ 'AL', 'AK', 'AR' ],
+ curr_value => $cgi->param('myfield'),
+
+ # recommended
+ id => 'myid', # DOM id
+
+ # optional
+ size => 1, # to show multiple rows at once
+ style => '', # STYLE property
+ multiple => 0,
+ disabled => 0,
+ onchange => 'do_something()',
+ js_only => 0, # disables the whole thing
+&>
+</%doc>
+
% unless ( $opt{'js_only'} ) {
<SELECT NAME = "<% $opt{field} %>"
diff --git a/httemplate/elements/tr-select-expire_months.html b/httemplate/elements/tr-select-expire_months.html
new file mode 100644
index 000000000..ced96603d
--- /dev/null
+++ b/httemplate/elements/tr-select-expire_months.html
@@ -0,0 +1,10 @@
+<& tr-select-months.html, @_ &>
+<script>
+// disable the pkgpart selector if it's set to zero months
+$().ready(function() {
+ $('#expire_months').on('change', function() {
+ $('#change_to_pkgpart').prop('disabled', this.value == 0);
+ })
+ .trigger('change');
+});
+</script>
diff --git a/httemplate/elements/tr-select-months.html b/httemplate/elements/tr-select-months.html
new file mode 100644
index 000000000..3ff28f99b
--- /dev/null
+++ b/httemplate/elements/tr-select-months.html
@@ -0,0 +1,12 @@
+<%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
+ };
+
+warn Dumper(\%opt);
+</%init>
+<& tr-select.html, %opt &>
diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html
index 41315701f..4903e185b 100755
--- a/httemplate/view/cust_main/packages.html
+++ b/httemplate/view/cust_main/packages.html
@@ -180,8 +180,11 @@ my @packages = $cust_main->all_pkgs( {
},
} );
+my $is_anything_hidden = 0; # optimization
+
my %change_to_from; # target pkgnum => current cust_pkg, for future changes
my %changed_from; # old pkgnum => new cust_pkg, for past changes
+my %supplementals_of; # main pkgnum => arrayref of supplementals
foreach my $cust_pkg ( @packages ) {
my %hash = $cust_pkg->hash;
@@ -190,18 +193,33 @@ foreach my $cust_pkg ( @packages ) {
$cust_pkg->{'_pkgpart'} = new FS::part_pkg \%part_pkg;
if ( $cust_pkg->change_to_pkgnum ) {
$change_to_from{$cust_pkg->change_to_pkgnum} = $cust_pkg;
+ $is_anything_hidden = 1;
}
if ( $cust_pkg->change_pkgnum ) {
$changed_from{$cust_pkg->change_pkgnum} = $cust_pkg;
+ $is_anything_hidden = 1;
+ }
+ if ( $cust_pkg->main_pkgnum ) {
+ $supplementals_of{$cust_pkg->main_pkgnum} ||= [];
+ push @{ $supplementals_of{$cust_pkg->main_pkgnum} }, $cust_pkg;
+ $is_anything_hidden = 1;
}
}
# filter out hidden package changes
-if ( keys %change_to_from or keys %changed_from ) {
+if ( $is_anything_hidden ) {
my @displayable_packages;
foreach my $cust_pkg (@packages) {
- if ( exists( $change_to_from{$cust_pkg->pkgnum} ) ) {
+ # if this package has any supplemental packages, it should remember them
+ $cust_pkg->set('_supplemental', $supplementals_of{$cust_pkg->pkgnum});
+
+ if ( $cust_pkg->main_pkgnum ) {
+
+ # it's a supplemental package of something else, and shouldn't be on the
+ # root list
+
+ } elsif ( exists( $change_to_from{$cust_pkg->pkgnum} ) ) {
# $cust_pkg is an ordered, not-yet-active package change target
my $change_from = $change_to_from{ $cust_pkg->pkgnum };
@@ -217,7 +235,9 @@ if ( keys %change_to_from or keys %changed_from ) {
$changed_to->set('changed_from_pkg', $cust_pkg);
} else {
+
push @displayable_packages, $cust_pkg;
+
}
}
@@ -252,7 +272,7 @@ $num_old_packages -= scalar(@packages);
# don't include supplemental packages in this list; they'll be found from
# their main packages
# (as will change-target packages)
-@packages = grep !$_->main_pkgnum, @packages;
+####@packages = grep !$_->main_pkgnum, @packages;
foreach my $cust_pkg ( @packages ) {
$cust_pkg->{'_cust_pkg_discount_active'} =
diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html
index 4b56e6fc4..8aa64039c 100644
--- a/httemplate/view/cust_main/packages/package.html
+++ b/httemplate/view/cust_main/packages/package.html
@@ -1,7 +1,6 @@
-<TD CLASS="inv package" BGCOLOR="<% $bgcolor %>" VALIGN="top" <%$style%>>
+<TD CLASS="inv package" BGCOLOR="<% $bgcolor %>" VALIGN="top">
+ <% join('', @marker ) %>
<TABLE CLASS="inv package">
-
-
<TR>
<TD COLSPAN=2>
<% $opt{before_pkg_callback}
@@ -107,7 +106,7 @@
% ) {
(&nbsp;<%pkg_event_link($cust_pkg)%>&nbsp;)
% }
-% } #!$supplemental
+% } # a canceled recurring package, or else no_links is in effect
</FONT>
</TD>
@@ -297,6 +296,7 @@
</TABLE>
% }
+ <% join('', map '</DIV>', @marker ) %>
</TD>
<%init>
@@ -317,16 +317,12 @@ my $statedefault = $opt{'statedefault'}
# if this package is somehow special
my $supplemental = $opt{'supplemental'} || 0;
my $change_from = $opt{'change_from'} || 0;
-my $style = '';
-if ( $supplemental or $change_from ) {
- $style = 'border-left-width: '.($supplemental + $change_from)*30 . 'px; '.
- 'border-color: ';
- if ( $supplemental ) {
- $style .= '#bbbbff';
- } elsif ( $change_from ) {
- $style .= '#bbffbb';
- }
- $style = qq!STYLE="$style"!;
+my @marker;
+if ( $supplemental ) {
+ push @marker, '<DIV CLASS="package-marker-supplemental">';
+}
+if ( $change_from ) {
+ push @marker, '<DIV CLASS="package-marker-change_from">';
}
$cust_pkg->pkgnum =~ /^(\d+)$/;
diff --git a/httemplate/view/cust_main/packages/section.html b/httemplate/view/cust_main/packages/section.html
index fe9f283c7..490f09c12 100755
--- a/httemplate/view/cust_main/packages/section.html
+++ b/httemplate/view/cust_main/packages/section.html
@@ -71,9 +71,11 @@
<& .packagerow, $cust_pkg->change_to_pkg, %iopt, 'change_from' => 1 &>
% }
% # include supplemental packages if any
-% $iopt{'supplemental'} = ($iopt{'supplemental'} || 0) + 1;
-% foreach my $supp_pkg ($cust_pkg->supplemental_pkgs) {
- <& .packagerow, $supp_pkg, %iopt &>
+% if ( $cust_pkg->_supplemental ) {
+% $iopt{'supplemental'} = ($iopt{'supplemental'} || 0) + 1;
+% foreach my $supp_pkg (@{ $cust_pkg->_supplemental }) {
+ <& .packagerow, $supp_pkg, %iopt &>
+% }
% }
</%def>
<%shared>
diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html
index 81156c927..7e125f72e 100644
--- a/httemplate/view/cust_main/packages/status.html
+++ b/httemplate/view/cust_main/packages/status.html
@@ -44,11 +44,11 @@
</TR>
% }
%
-% } else {
+% } else { # not canceled
%
% if ( $cust_pkg->get('susp') ) { #suspended or on hold
%
-% #if ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) { # inconsistent with FS::cust_pkg::status
+% #if ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) # inconsistent with FS::cust_pkg::status
% if ( ! $cust_pkg->setup ) { #status: on hold
<% pkg_status_row( $cust_pkg, emt('On Hold'), '', 'color'=>'7E0079', %opt ) %>
@@ -79,7 +79,7 @@
% } else {
<% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt ) %>
% }
-% }
+% }
<% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
@@ -97,7 +97,10 @@
<% pkg_status_row_expire($cust_pkg, %opt, curuser=>$curuser) %>
<% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
-% if ( !$supplemental && ! $opt{no_links} && !$change_from ) {
+% # Status changes for suspended packages: can unsuspend, future-unsuspend,
+% # or future-change. If this package is a future change or is supplemental
+% # disable them all.
+% if ( !$supplemental && ! $opt{no_links} && !$change_from ) {
<TR>
<TD COLSPAN=<%$opt{colspan}%>>
<FONT SIZE=-1>
@@ -203,7 +206,7 @@
<% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %>
-% } else {
+% } else { # recurring package
%
% my $num_cust_svc = $cust_pkg->num_cust_svc;
% my $summarize = $opt{'cust_pkg-large_pkg_size'} > 0
@@ -259,7 +262,11 @@
<% pkg_status_row_expire($cust_pkg, %opt, curuser=>$curuser) %>
<% pkg_status_row_if( $cust_pkg, emt('Contract ends'), 'contract_end', %opt ) %>
-% if ( $part_pkg->freq and !$supplemental && ! $opt{no_links} ) {
+% # Status changes for active recurring packages. If it has a future
+% # package change scheduled, let that be modified. If it's supplemental,
+% # then that's the only allowed action. Otherwise allow suspend, future
+% # suspend, do-not-suspend, and immediate and future cancel.
+% if ( $part_pkg->freq and ! $opt{no_links} ) {
<TR>
<TD COLSPAN=<%$opt{colspan}%>>
@@ -277,27 +284,29 @@
% }
% }
+% if ( !$supplemental ) {
% # suspension actions--always available
-% if ( $curuser->access_right('Suspend customer package') ) {
- (&nbsp;<% pkg_suspend_link($cust_pkg) %>&nbsp;)
-% }
-% if ( $curuser->access_right('Suspend customer package later') ) {
- (&nbsp;<% pkg_adjourn_link($cust_pkg) %>&nbsp;)
-% }
-% if ( $curuser->access_right('Delay suspension events') ) {
- (&nbsp;<% pkg_delay_link($cust_pkg) %>&nbsp;)
-% }
+% if ( $curuser->access_right('Suspend customer package') ) {
+ (&nbsp;<% pkg_suspend_link($cust_pkg) %>&nbsp;)
+% }
+% if ( $curuser->access_right('Suspend customer package later') ) {
+ (&nbsp;<% pkg_adjourn_link($cust_pkg) %>&nbsp;)
+% }
+% if ( $curuser->access_right('Delay suspension events') ) {
+ (&nbsp;<% pkg_delay_link($cust_pkg) %>&nbsp;)
+% }
%
-% if ( $change_from or $cust_pkg->change_to_pkgnum ) {
-% # you can't cancel the package while in this state
-% } else { # the normal case: links to cancel the package
- <BR>
-% if ( $curuser->access_right('Cancel customer package immediately') ) {
- (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
+% if ( $change_from or $cust_pkg->change_to_pkgnum ) {
+% # you can't cancel the package while in this state
+% } else { # the normal case: links to cancel the package
+ <BR>
+% if ( $curuser->access_right('Cancel customer package immediately') ) {
+ (&nbsp;<% pkg_cancel_link($cust_pkg) %>&nbsp;)
+% }
+% if ( $curuser->access_right('Cancel customer package later') ) {
+ (&nbsp;<% pkg_expire_link($cust_pkg) %>&nbsp;)
+% }
% }
-% if ( $curuser->access_right('Cancel customer package later') ) {
- (&nbsp;<% pkg_expire_link($cust_pkg) %>&nbsp;)
-% }
% }
<FONT>