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