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