ACL for hardware class config, RT#85057
[freeside.git] / FS / FS / access_right.pm
1 package FS::access_right;
2
3 use strict;
4 use vars qw( @ISA );
5 use Tie::IxHash;
6 use FS::Record qw( qsearch qsearchs );
7 use FS::upgrade_journal;
8 use FS::access_group;
9
10 @ISA = qw(FS::Record);
11
12 =head1 NAME
13
14 FS::access_right - Object methods for access_right records
15
16 =head1 SYNOPSIS
17
18   use FS::access_right;
19
20   $record = new FS::access_right \%hash;
21   $record = new FS::access_right { 'column' => 'value' };
22
23   $error = $record->insert;
24
25   $error = $new_record->replace($old_record);
26
27   $error = $record->delete;
28
29   $error = $record->check;
30
31 =head1 DESCRIPTION
32
33 An FS::access_right object represents a granted access right.  FS::access_right
34 inherits from FS::Record.  The following fields are currently supported:
35
36 =over 4
37
38 =item rightnum - primary key
39
40 =item righttype - 
41
42 =item rightobjnum - 
43
44 =item rightname - 
45
46
47 =back
48
49 =head1 METHODS
50
51 =over 4
52
53 =item new HASHREF
54
55 Creates a new right.  To add the right to the database, see L<"insert">.
56
57 Note that this stores the hash reference, not a distinct copy of the hash it
58 points to.  You can ask the object for a copy with the I<hash> method.
59
60 =cut
61
62 # the new method can be inherited from FS::Record, if a table method is defined
63
64 sub table { 'access_right'; }
65
66 =item insert
67
68 Adds this record to the database.  If there is an error, returns the error,
69 otherwise returns false.
70
71 =cut
72
73 # the insert method can be inherited from FS::Record
74
75 =item delete
76
77 Delete this record from the database.
78
79 =cut
80
81 # the delete method can be inherited from FS::Record
82
83 =item replace OLD_RECORD
84
85 Replaces the OLD_RECORD with this one in the database.  If there is an error,
86 returns the error, otherwise returns false.
87
88 =cut
89
90 # the replace method can be inherited from FS::Record
91
92 =item check
93
94 Checks all fields to make sure this is a valid right.  If there is
95 an error, returns the error, otherwise returns false.  Called by the insert
96 and replace methods.
97
98 =cut
99
100 # the check method should currently be supplied - FS::Record contains some
101 # data checking routines
102
103 sub check {
104   my $self = shift;
105
106   my $error = 
107     $self->ut_numbern('rightnum')
108     || $self->ut_text('righttype')
109     || $self->ut_text('rightobjnum')
110     || $self->ut_text('rightname')
111   ;
112   return $error if $error;
113
114   $self->SUPER::check;
115 }
116
117 # _upgrade_data
118 #
119 # Used by FS::Upgrade to migrate to a new database.
120
121 sub _upgrade_data { # class method
122   my ($class, %opts) = @_;
123
124   my @unmigrated = ( qsearch( 'access_right',
125                               { 'righttype'=>'FS::access_group',
126                                 'rightname'=>'Engineering configuration',
127                               }
128                             ), 
129                      qsearch( 'access_right',
130                               { 'righttype'=>'FS::access_group',
131                                 'rightname'=>'Engineering global configuration',
132                               }
133                             )
134                    ); 
135   foreach ( @unmigrated ) {
136     my $rightname = $_->rightname;
137     $rightname =~ s/Engineering/Dialup/;
138     $_->rightname($rightname);
139     my $error = $_->replace;
140     die "Failed to update access right: $error"
141       if $error;
142     my $broadband = new FS::access_right { $_->hash };
143     $rightname =~ s/Dialup/Broadband/;
144     $broadband->rightnum('');
145     $broadband->rightname($rightname);
146     $error = $broadband->insert;
147     die "Failed to insert access right: $error"
148       if $error;
149   }
150
151   my %migrate = (
152     'Post payment'    => [ 'Post check payment', 'Post cash payment' ],
153     'Process payment' => [ 'Process credit card payment', 'Process Echeck payment' ],
154     'Post refund'     => [ 'Post check refund', 'Post cash refund' ],
155     'Refund payment'  => [ 'Refund credit card payment', 'Refund Echeck payment' ],
156     'Regular void'    => [ 'Void payments' ],
157     'Unvoid'          => [ 'Unvoid payments', 'Unvoid invoices' ],
158     'Employees: Audit Report' => [ 'Employee Reports' ],
159   );
160
161   foreach my $oldright (keys %migrate) {
162     my @old = qsearch('access_right', { 'righttype'=>'FS::access_group',
163                                         'rightname'=>$oldright,
164                                       }
165                      );
166
167     foreach my $old ( @old ) {
168
169       foreach my $newright ( @{ $migrate{$oldright} } ) {
170         my %hash = (
171           'righttype'   => 'FS::access_group',
172           'rightobjnum' => $old->rightobjnum,
173           'rightname'   => $newright,
174         );
175         next if qsearchs('access_right', \%hash);
176         my $access_right = new FS::access_right \%hash;
177         my $error = $access_right->insert;
178         die $error if $error;
179       }
180
181       unless ( $oldright =~ / (payment|refund)$/ ) { #after the WEST stuff is sorted
182         my $error = $old->delete;
183         die $error if $error;
184       }
185
186     }
187
188   }
189
190   my @all_groups = qsearch('access_group', {});
191
192   #tie my %onetime, 'Tie::IxHash',
193   my @onetime = (
194     'List customers'                      => 'List all customers',
195     'List all customers'                  => 'Advanced customer search',
196     'List packages'                       => 'Summarize packages',
197     'Post payment'                        => 'Backdate payment',
198     'Cancel customer package immediately' => 'Un-cancel customer package',
199     'Suspend customer package'            => 'Suspend customer',
200     'Unsuspend customer package'          => 'Unsuspend customer',
201     'New prospect'                        => 'Generate quotation',
202     'Delete invoices'                     => 'Void invoices',
203     'List invoices'                       => 'List quotations',
204     'Post credit'                         => 'Credit line items',
205     #'View customer tax exemptions'        => 'Edit customer tax exemptions',
206     'Edit customer'                       => 'Edit customer tax exemptions',
207     'Edit package definitions'            => 'Bulk edit package definitions',
208
209     'List services'    => [ 'Services: Accounts',
210                             'Services: Domains',
211                             'Services: Certificates',
212                             'Services: Mail forwards',
213                             'Services: Virtual hosting services',
214                             'Services: Wireless broadband services',
215                             'Services: DSLs',
216                             'Services: Dish services',
217                             'Services: Hardware',
218                             'Services: Phone numbers',
219                             'Services: PBXs',
220                             'Services: Ports',
221                             'Services: Mailing lists',
222                             'Services: External services',
223                           ],
224
225     'Services: Accounts' => 'Services: Accounts: Advanced search',
226     'Services: Wireless broadband services' => 'Services: Wireless broadband services: Advanced search',
227     'Services: Hardware' => 'Services: Hardware: Advanced search',
228     'Services: Phone numbers' => 'Services: Phone numbers: Advanced search',
229
230     'Services: Accounts' => 'Services: Alarm services',
231
232     'List rating data' => [ 'Usage: RADIUS sessions',
233                             'Usage: Call Detail Records (CDRs)',
234                             'Usage: Unrateable CDRs',
235                           ],
236     'Provision customer service' => [ 'Edit password' ],
237     'Financial reports' => 'Employee Reports',
238     'Change customer package' => 'Detach customer package',
239     'Services: Accounts' => 'Services: Cable Subscribers',
240     'Bulk change customer packages' => 'Bulk move customer services',
241     'Configuration' => 'Edit sales people',
242     'Configuration' => 'Alarm global configuration',
243     'Services: Accounts' => 'Services: Conferencing',
244     'Services: Accounts' => 'Services: Video',
245     'Edit global package definitions' => 'Edit package definition costs',
246     'Add on-the-fly credit reason' => 'Add on-the-fly refund reason',
247     'Configuration' => 'Edit global fee definitions',
248     'Edit package definition costs' => 'View package definition costs',
249     'List prospects' => 'List contacts',
250     'List customers' => 'List contacts',
251     'Backdate payment' => 'Backdate credit',
252     'Generate quotation' => 'Disable quotation',
253     'Add on-the-fly void credit reason' => 'Add on-the-fly void reason',
254     '_ALL' => 'Employee preference telephony integration',
255     '_ALL' => 'RT activity notification',
256     'Edit customer package dates' => [ 'Change package start date', #4.x
257                                        'Change package contract end date',
258                                      ],
259     'Resend invoices' => 'Print and mail invoices',
260     'List customers' => 'Customers: Customer churn report',
261     'Edit customer note' => 'Delete customer note',
262     'Edit customer' => 'Edit customer invoice terms',
263     'Financial reports' => 'Basic payment and refund reports',
264     'Configuration' => 'Edit hardware clases and types',
265   );
266
267 #  foreach my $old_acl ( keys %onetime ) {
268 #
269 #    my @new_acl = ref($onetime{$old_acl})
270 #                    ? @{ $onetime{$old_acl} }
271 #                    :  ( $onetime{$old_acl} );
272
273   while ( @onetime ) {
274
275     my( $old_acl, $new_acl ) = splice(@onetime, 0, 2);
276     my @new_acl = ref($new_acl) ? @$new_acl : ( $new_acl );
277
278     foreach my $new_acl ( @new_acl ) {
279
280       ( my $journal = 'ACL_'.lc($new_acl) ) =~ s/\W/_/g;
281       next if FS::upgrade_journal->is_done($journal);
282
283       # grant $new_acl to all groups who have $old_acl
284       for my $group (@all_groups) {
285         next unless $old_acl eq '_ALL' || $group->access_right($old_acl);
286         next if     $group->access_right($new_acl);
287         my $access_right = FS::access_right->new( {
288             'righttype'   => 'FS::access_group',
289             'rightobjnum' => $group->groupnum,
290             'rightname'   => $new_acl,
291         } );
292         my $error = $access_right->insert;
293         die $error if $error;
294       }
295     
296       FS::upgrade_journal->set_done($journal);
297
298     }
299
300   }
301
302   # some false laziness with @onetime above,
303   # but for use when multiple old acls trigger a single new acl
304   # (keys/values reversed from @onetime, expects arrayref value)
305   my @onetime_bynew = (
306     'Customize billing during suspension' => [ 'Suspend customer package', 'Suspend customer package later' ],
307   );
308   while ( @onetime_bynew ) {
309     my( $new_acl, $old_acl ) = splice(@onetime_bynew, 0, 2);
310     ( my $journal = 'ACL_'.lc($new_acl) ) =~ s/\W/_/g;
311     next if FS::upgrade_journal->is_done($journal);
312     # grant $new_acl to all groups who have one of @old_acl
313     for my $group (@all_groups) {
314       next unless grep { $group->access_right($_) } @$old_acl;
315       next if     $group->access_right($new_acl);
316       my $access_right = FS::access_right->new( {
317           'righttype'   => 'FS::access_group',
318           'rightobjnum' => $group->groupnum,
319           'rightname'   => $new_acl,
320       } );
321       my $error = $access_right->insert;
322       die $error if $error;
323     }
324     
325     FS::upgrade_journal->set_done($journal);
326
327   }
328
329   ### ACL_download_report_data
330   if ( !FS::upgrade_journal->is_done('ACL_download_report_data') ) {
331
332     # grant to everyone
333     for my $group (@all_groups) {
334       next if $group->access_right('Download report data');
335       my $access_right = FS::access_right->new( {
336           'righttype'   => 'FS::access_group',
337           'rightobjnum' => $group->groupnum,
338           'rightname'   => 'Download report data',
339       } );
340       my $error = $access_right->insert;
341       warn $error if $error;
342     }
343
344     FS::upgrade_journal->set_done('ACL_download_report_data');
345   }
346
347   '';
348
349 }
350
351 =back
352
353 =head1 BUGS
354
355 =head1 SEE ALSO
356
357 L<FS::Record>, schema.html from the base documentation.
358
359 =cut
360
361 1;
362