<% join('', @marker ) %> % ### % # Quantity % ### % if ( $cust_pkg->quantity > 1 ) { % } % ### % # Sales person % ### % if ( $cust_pkg->salesnum ) { % } % ### % # Invoice details & comments % ### % my $editi = $curuser->access_right('Edit customer package invoice details'); % my $editc = $curuser->access_right('Edit customer package comments'); % my @cust_pkg_detail = $cust_pkg->cust_pkg_detail; % my @invoice_detail = grep { $_->detailtype eq 'I' } @cust_pkg_detail; % my @comments = grep { $_->detailtype eq 'C' } @cust_pkg_detail; % % if ( scalar(@invoice_detail) || scalar(@comments) || $editi || $editc ) { % % my $editlink = $p. 'edit/cust_pkg_detail.html?pkgnum='. $cust_pkg->pkgnum. % ';detailtype='; % if ( @invoice_detail ) { % foreach my $cust_pkg_detail ( @invoice_detail ) { % }
<% $opt{before_pkg_callback} ? &{ $opt{before_pkg_callback} }( $cust_pkg ) : '' %> % ### % # Package % ### <% $opt{show_pkgnum} ? $cust_pkg->pkgnum.': ' : '' %><% $part_pkg->pkg |h %> % % my $custom_comment; % if ( 0 && FS::part_pkg::flat->can('price_info') eq $part_pkg->can('price_info') ) { % #perf hack / disabled in 4.x (feature pricing / cust_pkg_usageprice incompatible, well, harder) % % $part_pkg->{"_$_"} = $part_pkg->option($_) || 0 % foreach grep !defined($part_pkg->{"_$_"} ), qw(setup_fee recur_fee); % % my $str = ''; % $str = $opt{money_char} . $part_pkg->{_setup_fee}. % ($part_pkg->{_recur_fee} ? ' setup' : ' one-time') % if $part_pkg->{_setup_fee}; % $str .= ', ' if $part_pkg->{_setup_fee} && $part_pkg->{_recur_fee}; % $str .= $opt{money_char}. $part_pkg->{_recur_fee}. % '/'. $part_pkg->freq_pretty % if $part_pkg->{_recur_fee}; % $str; % % $custom_comment = % ( $part_pkg->custom ? '(CUSTOM) ' : '' ). % $part_pkg->comment. % ( ($part_pkg->custom || $part_pkg->comment) ? ' - ' : '' ). % ($str || 'No charge'); % % } else { % $custom_comment = $part_pkg->custom_comment('cust_pkg'=>$cust_pkg); % } <% $custom_comment ? ' - ' : '' %> <% $custom_comment |h %>
      <% mt('Quantity:') |h %> <% $cust_pkg->quantity %> % if ( $curuser->access_right('Change customer package') % && ! $cust_pkg->get('cancel') % && ! $change_from % && ! $supplemental % && $part_pkg->freq ne '0' % && ! $opt{no_links} % && $opt{'invoice-unitprice'} % ) % { ( <% pkg_change_quantity_link($cust_pkg, 'change') %> ) % }
      <% mt('Sales Person:') |h %> <% $cust_pkg->salesperson |h %> % if ( $curuser->access_right('Change customer package') % && ! $cust_pkg->get('cancel') % && ! $change_from % && ! $supplemental % #&& $part_pkg->freq ne '0' % && ! $opt{no_links} % ) % { ( <% pkg_change_salesnum_link($cust_pkg, 'change') %> ) % }
<& /elements/table-grid.html &>
<% mt('Invoice details') |h %> % if ( $editi && ! $cust_pkg->get('cancel') && ! $opt{no_links} ) { (<& /elements/popup_link.html, { 'action' => $editlink. 'I', 'label' => emt('edit'), 'actionlabel' => emt('Edit invoice details'), 'color' => '#333399', 'width' => 763, } &>) % }
 - <% $cust_pkg_detail->detail |h %>
% } else { % } % if ( @comments ) { <& /elements/table-grid.html &> <% mt('Comments') |h %> % if ( $editc && ! $opt{no_links} ) { (<& /elements/popup_link.html, { 'action' => $editlink. 'C', 'label' => emt('edit'), 'actionlabel' => emt('Edit comments'), 'color' => '#333399', 'width' => 763, } &>) % } % foreach my $cust_pkg_detail ( @comments ) {  - <% $cust_pkg_detail->detail |h %> % } % } else { % } % } % if ( @cust_pkg_usage ) { % foreach my $usage (@cust_pkg_usage) { % my $part = $usage->part_pkg_usage; % my $ratio = 255 * ($usage->minutes / $part->minutes); % $ratio = 255 if $ratio > 255; # because rollover % my $color = sprintf('STYLE="font-weight: bold; color: #%02x%02x00"', 255 - $ratio, $ratio); % my $trstyle = ''; % $trstyle = ' CLASS="shared"' if $part->shared; > % if ( $part->shared ) { % } % }
<% emt('Included usage') %>
<% $part->description %>: ALIGN="right"><% sprintf('%.1f', $usage->minutes) %> > / ><% $part->minutes %>(shared)
% } % ### % # Package actions dropdown % ### % unless ( $opt{no_links} ) {
% my $plink = "pkgnum=$pkgnum"; % my $reg_recur_cond = sub { $part_pkg->freq ne '0' % && ! $change_from % && ! $supplemental % && ! $cust_pkg->get('cancel') % }; % my $change_cond = sub { $part_pkg->freq ne '0' % && ! $change_from % && ! $supplemental % && ! $cust_pkg->get('cancel') % && $cust_pkg->change_to_pkgnum, % }; <& /elements/dropdown-menu.html, id => 'cust_pkg'. $cust_pkg->pkgnum. '_menu', bgcolor => $opt{row} % 2 ? '#ffffff' : '#eeeeee', menu => [ [ #TODO: order/group these better { label => 'Package actions', content => ''. 'Package actions'. ' ', }, { label => 'Modify one-time charge', acl => 'Modify one-time charge', condition => sub { $part_pkg->freq eq '0' }, url => "edit/quick-charge.html?change_$plink", }, { label => 'Change package', acl => 'Change customer package', condition => $reg_recur_cond, popup => "misc/change_pkg.cgi?$plink". ';locationnum='. $cust_pkg->locationnum, actionlabel => emt('Change package'), #width => 768, width => 960, height => 640, }, { label => 'Discount package', condition => sub { ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && $can_discount_pkg }, popup => "edit/cust_pkg_discount.html?$plink", actionlabel => emt('Discount package'), width => 616, }, { label => 'Customize package', acl => 'Customize customer package', condition => $reg_recur_cond, url => "edit/part_pkg.cgi?$plink". ';clone='. $part_pkg->pkgpart, }, { label => '-', content => '-', }, { label => 'View package events', acl => [ 'Billing event reports', 'View customer billing events', ], condition => sub { $cust_pkg->exists_cust_event }, url => "search/cust_event.html?$plink", }, { label => '-', condition => sub { $cust_pkg->exists_cust_event }, content => '-', }, { label => 'Change quantity', acl => 'Change customer package', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && $opt{'invoice-unitprice'} }, popup => "edit/cust_pkg_quantity.html?$plink", actionlabel => emt('Change quantity'), width => 390, height => 220, }, { label => 'Change sales person', acl => 'Change customer package', condition => sub { ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') }, popup => "edit/cust_pkg_salesnum.html?$plink", actionlabel => emt('Change sales persion'), width => 390, height => 220, }, { label => '-', content => '-', }, { label => (@invoice_detail ? 'Edit' : 'Add'). ' invoice details', acl => 'Edit customer package invoice details', condition => sub { ! $cust_pkg->get('cancel') }, popup => "edit/cust_pkg_detail.html?$plink". ';detailtype=I', actionlabel => emt( (@invoice_detail ? 'Edit' : 'Add'). ' invoice details' ), width => 768, }, { label => (@comments ? 'Edit' : 'Add'). ' comments', acl => 'Edit customer package comments', popup => "edit/cust_pkg_detail.html?$plink". ';detailtype=C', actionlabel => emt( (@comments ? 'Edit' : 'Add'). ' comments' ), width => 768, }, { label => '-', #condition => sub { $part_pkg->freq ne '0' }, content => '-', }, { label => 'Set start date', acl => 'Change package start date', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && ! $cust_pkg->get('setup') }, popup => "misc/change_pkg_date.html?$plink". ';field=start_date', actionlabel => emt('Set start of billing for'), width => 510, height => 310, }, { label => 'Set contract end', acl => 'Change package contract end date', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && ! $cust_pkg->change_to_pkgnum }, popup => "misc/change_pkg_date.html?$plink". ';field=contract_end', actionlabel => emt('Set contract end for'), width => 510, height => 310, }, { label => '-', condition => sub { $part_pkg->freq ne '0' }, content => '-', }, { label => 'Change now', acl => 'Change customer package', condition => $change_cond, url => "misc/change_pkg_now.cgi?$pkgnum", }, { label => 'Reschedule', acl => 'Change customer package', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && $cust_pkg->change_to_pkgnum, }, popup => "misc/change_pkg.html?$plink", actionlabel => emt('Edit scheduled change for'), url => "misc/change_pkg_now.cgi?$pkgnum", width => 960, height => 490, }, { label => 'Abort change', acl => 'Change customer package', condition => $change_cond, url => "misc/do_not_change_pkg.cgi?$pkgnum", }, { label => '-', acl => 'Change customer package', condition => $change_cond, content => '-', }, { label => 'Suspend now', acl => 'Suspend customer package', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && ! $cust_pkg->get('susp') }, popup => "misc/cancel_pkg.html?method=suspend;$plink", actionlabel => emt('Suspend now'), color => '#FF9900', width => 768, height => 420, }, { label => 'Suspend later', acl => 'Suspend customer package later', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && ! $cust_pkg->get('susp') }, popup => "misc/cancel_pkg.html?method=adjourn;$plink", actionlabel => emt('Suspend later'), color => '#CC6600', width => 768, height => 445, }, { label => $cust_pkg->dundate ? 'Edit suspension delay' : 'Delay suspend', acl => 'Delay suspension events', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && ! $cust_pkg->get('susp') }, popup => "misc/delay_susp_pkg.html?$plink", actionlabel => emt('Delay suspend for'), width => 768, }, { label => 'Start billing', acl => 'Unsuspend customer package', condition => sub { ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && $cust_pkg->get('susp') && $cust_pkg->order_date == $cust_pkg->get('susp') }, popup => "misc/unhold_pkg.html?$plink", actionlabel => emt('Start billing'), color => '#00CC00', width => 510, height => 310, }, { label => 'Unsuspend now', acl => 'Unsuspend customer package', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && $cust_pkg->get('susp') && $cust_pkg->order_date != $cust_pkg->get('susp') }, 'url' => "misc/unsusp_pkg.cgi?$pkgnum", }, { label => 'Unsuspend later', acl => 'Unsuspend customer package', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && $cust_pkg->get('susp') && $cust_pkg->order_date != $cust_pkg->get('susp') }, popup => "misc/cancel_pkg.html?method=resume;$plink", actionlabel => emt('Unsuspend later'), color => '#00CC00', width => 768, }, { label => '-', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->get('cancel') && ! $cust_pkg->get('susp') }, content => '-', }, { label => 'Cancel now', acl => 'Cancel customer package immediately', condition => sub { ( $part_pkg->freq ne '0' || ! $cust_pkg->get('setup') ) && ! $change_from && ! $supplemental && ! $cust_pkg->change_to_pkgnum && ! $cust_pkg->get('cancel') }, popup => "misc/cancel_pkg.html?method=cancel;$plink", actionlabel => emt('Cancel now'), color => '#FF0000', width => 768, }, { label => 'Cancel later', acl => 'Cancel customer package later', condition => sub { $part_pkg->freq ne '0' && ! $change_from && ! $supplemental && ! $cust_pkg->change_to_pkgnum && ! $cust_pkg->get('cancel') }, popup => "misc/cancel_pkg.html?method=expire;$plink", actionlabel => emt('Cancel later'), color => '#CC0000', width => 768, }, { label => 'Un-cancel', acl => 'Un-cancel customer package', condition => sub { $part_pkg->freq ne '0' && ! $supplemental && ! $cust_pkg->change_custnum && $cust_pkg->get('cancel') }, popup => "misc/cancel_pkg.html?method=uncancel;$plink", actionlabel => emt('Un-cancel'), width => 960, height => 740, }, { label => '-', condition => sub { ( $part_pkg->freq ne '0' || ! $cust_pkg->get('setup') ) && ! $change_from && ! $cust_pkg->get('cancel') }, content => '-', }, { label => 'Add contact', #acl => 'Add package contact',#or something like that condition => sub { ! $cust_pkg->get('cancel') }, popup => "misc/change_pkg_contact.html?$plink", actionlabel => emt('Add contact'), width => 616, height => 200, }, { label => 'Change location', acl => 'Change customer package', condition => sub { ! $change_from }, popup => "misc/change_pkg.cgi?locationnum=-1;$plink;". "address1=;address2=;city=;county=;state=$statedefault;". "zip=;country=$countrydefault", actionlabel => emt('Change location'), width => 960, height => 640, }, { label => 'Edit location', acl => 'Change customer package', condition => sub { ! $change_from && $cust_pkg->locationnum != $cust_pkg->cust_main->ship_locationnum }, popup => 'edit/cust_location.cgi?locationnum='. $cust_pkg->locationnum, actionlabel => emt('Edit location'), width => 700, height => 355, }, ], ], &>
% } <% join('', map '', @marker ) %> <%init> my %opt = @_; my $bgcolor = $opt{'bgcolor'}; my $cust_pkg = $opt{'cust_pkg'}; my $part_pkg = $opt{'part_pkg'}; my $curuser = $FS::CurrentUser::CurrentUser; my $countrydefault = $opt{'countrydefault'} || 'US'; my $statedefault = $opt{'statedefault'} || ($countrydefault eq 'US' ? 'CA' : ''); # put a marker on the left edge of this column # if this package is somehow special my $supplemental = $opt{'supplemental'} || 0; my $change_from = $opt{'change_from'} || 0; my @marker; if ( $supplemental ) { push @marker, '
'; } if ( $change_from ) { push @marker, '
'; } $cust_pkg->pkgnum =~ /^(\d+)$/; my $pkgnum = $1; my @cust_pkg_usage = qsearch({ 'select' => 'cust_pkg_usage.*', 'table' => 'cust_pkg_usage', 'addl_from' => ' JOIN part_pkg_usage USING (pkgusagepart)', 'extra_sql' => " WHERE pkgnum = $1", 'order_by' => ' ORDER BY priority ASC, description ASC', }); #subroutines #false laziness w/status.html sub pkg_link { my($action, $label, $cust_pkg) = @_; return '' unless $cust_pkg; qq!$label!; } sub pkg_change_location_link { my $cust_pkg = shift; my $pkgpart = $cust_pkg->pkgpart; include( '/elements/popup_link-cust_pkg.html', 'action' => $p. "misc/change_pkg.cgi?locationnum=-1;pkgpart=$pkgpart;". "address1=;address2=;city=;county=;state=$statedefault;". "zip=;country=$countrydefault", 'label' => emt('Change location'), 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, 'width' => 960, 'height' => 530, ); } sub pkg_change_quantity_link { my( $cust_pkg, $label ) = @_; include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'edit/cust_pkg_quantity.html?', 'label' => emt($label), 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, 'width' => 390, 'height' => 220, ); } sub pkg_change_salesnum_link { my( $cust_pkg, $label ) = @_; include( '/elements/popup_link-cust_pkg.html', 'action' => $p. 'edit/cust_pkg_salesnum.html?', 'label' => emt($label), 'actionlabel' => emt('Change'), 'cust_pkg' => $cust_pkg, 'width' => 390, 'height' => 220, ); } # figure out if this user will be able to edit either the setup or recurring # discounts for this package my $can_discount_pkg = 0; if ( $part_pkg->can_discount ) { #looking these up individually uses the ACL cache and is a big win for lots # of packages my $discount = $curuser->access_right('Discount customer package'); my $waive = $curuser->access_right('Waive setup fee'); $can_discount_pkg = ( ($discount || $waive) && $cust_pkg->base_setup > 0 && !$cust_pkg->setup or ( $discount && $cust_pkg->base_recur > 0 && $cust_pkg->freq ne '0' ) ); }