further work on agents editing own packages: allow them to see (but not edit) global...
[freeside.git] / httemplate / browse / part_pkg.cgi
1 <% include( 'elements/browse.html',
2                  'title'                 => 'Package Definitions',
3                  'html_init'             => $html_init,
4                  'name'                  => 'package definitions',
5                  'disableable'           => 1,
6                  'disabled_statuspos'    => 3,
7                  'agent_virt'            => 1,
8                  'agent_null_right'      => [ $edit, $edit_global ],
9                  'agent_null_right_link' => $edit_global,
10                  'agent_pos'             => 5,
11                  'query'                 => { 'select'    => $select,
12                                               'table'     => 'part_pkg',
13                                               'hashref'   => {},
14                                               'extra_sql' => $extra_sql,
15                                               'order_by'  => "ORDER BY $orderby"
16                                             },
17                  'count_query'           => $count_query,
18                  'header'                => \@header,
19                  'fields'                => \@fields,
20                  'links'                 => \@links,
21                  'align'                 => $align,
22              )
23 %>
24 <%init>
25
26 my $curuser = $FS::CurrentUser::CurrentUser;
27
28 my $edit        = 'Edit package definitions';
29 my $edit_global = 'Edit global package definitions';
30 my $acl_edit        = $curuser->access_right($edit);
31 my $acl_edit_global = $curuser->access_right($edit_global);
32 my $acl_config      = $curuser->access_right('Configuration'); #to edit services
33
34 die "access denied"
35   unless $acl_edit || $acl_edit_global;
36
37 my $conf = new FS::Conf;
38 my $taxclasses = $conf->exists('enable_taxclasses');
39 my $money_char = $conf->config('money_char') || '$';
40
41 my $select = '*';
42 my $orderby = 'pkgpart';
43 if ( $cgi->param('active') ) {
44   $orderby = 'num_active DESC';
45 }
46
47 my $extra_sql = '';
48
49 my $agentnums = join(',', $curuser->agentnums);
50
51 unless ( $acl_edit_global ) {
52   $extra_sql .= "
53     WHERE (
54       agentnum IS NOT NULL OR 0 < (
55         SELECT COUNT(*)
56           FROM type_pkgs
57             LEFT JOIN agent_type USING ( typenum )
58             LEFT JOIN agent AS typeagent USING ( typenum )
59           WHERE type_pkgs.pkgpart = part_pkg.pkgpart
60             AND typeagent.agentnum IN ($agentnums)
61       )
62     )
63   ";
64 }
65
66 my $count_cust_pkg = "
67   SELECT COUNT(*) FROM cust_pkg LEFT JOIN cust_main USING ( custnum )
68     WHERE cust_pkg.pkgpart = part_pkg.pkgpart
69       AND cust_main.agentnum IN ($agentnums)
70 ";
71
72 $select = "
73
74   *,
75
76   ( $count_cust_pkg
77       AND ( cancel IS NULL OR cancel = 0 )
78       AND ( susp IS NULL OR susp = 0 )
79   ) AS num_active,
80
81   ( $count_cust_pkg
82       AND ( cancel IS NULL OR cancel = 0 )
83       AND susp IS NOT NULL AND susp != 0
84   ) AS num_suspended,
85
86   ( $count_cust_pkg
87       AND cancel IS NOT NULL AND cancel != 0
88   ) AS num_cancelled
89
90 ";
91
92 my $html_init;
93 #unless ( $cgi->param('active') ) {
94   $html_init = qq!
95     One or more service definitions are grouped together into a package 
96     definition and given pricing information.  Customers purchase packages
97     rather than purchase services directly.<BR><BR>
98     <A HREF="${p}edit/part_pkg.cgi"><I>Add a new package definition</I></A>
99     <BR><BR>
100   !;
101 #}
102
103 # ------
104
105 my $link = [ $p.'edit/part_pkg.cgi?', 'pkgpart' ];
106
107 my @header = ( '#', 'Package', 'Comment' );
108 my @fields = ( 'pkgpart', 'pkg', 'comment' );
109 my $align = 'rll';
110 my @links = ( $link, $link, '' );
111
112 unless ( 0 ) { #already showing only one class or something?
113   push @header, 'Class';
114   push @fields, sub { shift->classname || '(none)'; };
115   $align .= 'l';
116 }
117
118 tie my %plans, 'Tie::IxHash', %{ FS::part_pkg::plan_info() };
119
120 tie my %plan_labels, 'Tie::IxHash',
121   map {  $_ => ( $plans{$_}->{'shortname'} || $plans{$_}->{'name'} ) }
122       keys %plans;
123
124 push @header, 'Pricing';
125 $align .= 'r'; #?
126 push @fields, sub {
127   my $part_pkg = shift;
128   (my $plan = $plan_labels{$part_pkg->plan} ) =~ s/ /&nbsp;/g;
129   my $is_recur = ( $part_pkg->freq ne '0' );
130
131   [
132     [
133       { data =>$plan,
134         align=>'center',
135         colspan=>2,
136       },
137     ],
138     [
139       { data =>$money_char.
140                sprintf('%.2f', $part_pkg->option('setup_fee') ),
141         align=>'right'
142       },
143       { data => ( $is_recur ? ' setup' : ' one-time' ),
144         align=>'left',
145       },
146     ],
147     [
148       { data=>( $is_recur
149                   ? $money_char.sprintf('%.2f ', $part_pkg->option('recur_fee') )
150                   : $part_pkg->freq_pretty
151               ),
152         align=> ( $is_recur ? 'right' : 'center' ),
153         colspan=> ( $is_recur ? 1 : 2 ),
154       },
155       ( $is_recur
156         ?  { data => ( $is_recur ? $part_pkg->freq_pretty : '' ),
157              align=>'left',
158            }
159         : ()
160       ),
161     ],
162     ( map { 
163             my $dst_pkg = $_->dst_pkg;
164             [ 
165               { data => 'Add-on:&nbsp;'.$dst_pkg->pkg_comment,
166                 align=>'center', #?
167                 colspan=>2,
168               }
169             ]
170           }
171       $part_pkg->bill_part_pkg_link
172     ),
173   ];
174
175 #  $plan_labels{$part_pkg->plan}.'<BR>'.
176 #    $money_char.sprintf('%.2f setup<BR>', $part_pkg->option('setup_fee') ).
177 #    ( $part_pkg->freq ne '0'
178 #      ? $money_char.sprintf('%.2f ', $part_pkg->option('recur_fee') )
179 #      : ''
180 #    ).
181 #    $part_pkg->freq_pretty; #.'<BR>'
182 };
183
184 #if ( $cgi->param('active') ) {
185   push @header, 'Customer<BR>packages';
186   my %col = (
187     'active'          => '00CC00',
188     'suspended'       => 'FF9900',
189     'cancelled'       => 'FF0000',
190     #'one-time charge' => '000000',
191     'charge'          => '000000',
192   );
193   my $cust_pkg_link = $p. 'search/cust_pkg.cgi?pkgpart=';
194   push @fields, sub { my $part_pkg = shift;
195                       [
196                         map {
197                               my $magic = $_;
198                               my $label = $_;
199                               if ( $magic eq 'active' && $part_pkg->freq == 0 ) {
200                                 $magic = 'inactive';
201                                 #$label = 'one-time charge',
202                                 $label = 'charge',
203                               }
204                           
205                               [
206                                 {
207                                  'data'  => '<B><FONT COLOR="#'. $col{$label}. '">'.
208                                             $part_pkg->get("num_$_").
209                                             '</FONT></B>',
210                                  'align' => 'right',
211                                 },
212                                 {
213                                  'data'  => $label.
214                                               ( $part_pkg->get("num_$_") != 1
215                                                 && $label =~ /charge$/
216                                                   ? 's'
217                                                   : ''
218                                               ),
219                                  'align' => 'left',
220                                  'link'  => ( $part_pkg->get("num_$_")
221                                                 ? $cust_pkg_link.
222                                                   $part_pkg->pkgpart.
223                                                   ";magic=$magic"
224                                                 : ''
225                                             ),
226                                 },
227                               ],
228                             } (qw( active suspended cancelled ))
229                       ]; };
230   $align .= 'r';
231 #}
232
233 if ( $taxclasses ) {
234   push @header, 'Taxclass';
235   push @fields, sub { shift->taxclass() || '&nbsp;'; };
236   $align .= 'l';
237 }
238
239 push @header, 'Plan options',
240               'Services';
241               #'Service', 'Quan', 'Primary';
242
243 push @fields, 
244               sub {
245                     my $part_pkg = shift;
246                     if ( $part_pkg->plan ) {
247
248                       my %options = $part_pkg->options;
249
250                       [ map { 
251                               [
252                                 { 'data'  => $_,
253                                   'align' => 'right',
254                                 },
255                                 { 'data'  => $part_pkg->format($_,$options{$_}),
256                                   'align' => 'left',
257                                 },
258                               ];
259                             }
260                         grep { $options{$_} =~ /\S/ } 
261                         grep { $_ !~ /^(setup|recur)_fee$/ }
262                         keys %options
263                       ];
264
265                     } else {
266
267                       [ map { [
268                                 { 'data'  => uc($_),
269                                   'align' => 'right',
270                                 },
271                                 {
272                                   'data'  => $part_pkg->$_(),
273                                   'align' => 'left',
274                                 },
275                               ];
276                             }
277                         (qw(setup recur))
278                       ];
279
280                     }
281
282                   },
283
284               sub {
285                     my $part_pkg = shift;
286
287                     [ 
288                       (map {
289                              my $pkg_svc = $_;
290                              my $part_svc = $pkg_svc->part_svc;
291                              my $svc = $part_svc->svc;
292                              if ( $pkg_svc->primary_svc =~ /^Y/i ) {
293                                $svc = "<B>$svc (PRIMARY)</B>";
294                              }
295                              $svc =~ s/ +/&nbsp;/g;
296
297                              [
298                                {
299                                  'data'  => '<B>'. $pkg_svc->quantity. '</B>',
300                                  'align' => 'right'
301                                },
302                                {
303                                  'data'  => $svc,
304                                  'align' => 'left',
305                                  'link'  => ( $acl_config
306                                                 ? $p. 'edit/part_svc.cgi?'.
307                                                   $part_svc->svcpart
308                                                 : ''
309                                             ),
310                                },
311                              ];
312                            }
313                       sort {     $b->primary_svc =~ /^Y/i
314                              <=> $a->primary_svc =~ /^Y/i
315                            }
316                            $part_pkg->pkg_svc('disable_linked'=>1)
317                       ),
318                       ( map { 
319                               my $dst_pkg = $_->dst_pkg;
320                               [
321                                 { data => 'Add-on:&nbsp;'.$dst_pkg->pkg_comment,
322                                   align=>'center', #?
323                                   colspan=>2,
324                                 }
325                               ]
326                             }
327                         $part_pkg->svc_part_pkg_link
328                       )
329                     ];
330
331                   };
332
333 $align .= 'lrl'; #rr';
334
335 # --------
336
337 my $count_query = "SELECT COUNT(*) FROM part_pkg $extra_sql";
338
339 </%init>