]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Reporter.pm
added cascading delete support for reports and templates
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Reporter.pm
1 package OpenILS::Application::Reporter;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
4 use OpenSRF::Utils::Logger qw/$logger/;
5 use OpenILS::Utils::CStoreEditor qw/:funcs/;
6 use OpenILS::Utils::Fieldmapper;
7 use OpenILS::Application::AppUtils;
8 my $U = "OpenILS::Application::AppUtils";
9
10
11 __PACKAGE__->register_method(
12         api_name => 'open-ils.reporter.folder.create',
13         method => 'create_folder'
14 );
15
16 sub create_folder {
17         my( $self, $conn, $auth, $type, $folder ) = @_;
18
19         my $e = new_rstore_editor(xact=>1, authtoken=>$auth);
20         return $e->die_event unless $e->checkauth;
21         return $e->die_event unless $e->allowed('RUN_REPORTS');
22
23         return 0 if $folder->owner ne $e->requestor->id;
24
25         $folder->owner($e->requestor->id);
26         my $meth = "create_reporter_${type}_folder";
27         $e->$meth($folder) or return $e->die_event;
28         $e->commit;
29
30         return $folder->id;
31 }
32
33
34 __PACKAGE__->register_method(
35         api_name => 'open-ils.reporter.folder.visible.retrieve',
36         method => 'retrieve_visible_folders'
37 );
38
39 sub retrieve_visible_folders {
40         my( $self, $conn, $auth, $type ) = @_;
41         my $e = new_rstore_editor(authtoken=>$auth);
42         return $e->event unless $e->checkauth;
43         return $e->event unless $e->allowed('RUN_REPORTS');
44
45         my $class = 'rrf';
46         $class = 'rtf' if $type eq 'template';
47         $class = 'rof' if $type eq 'output';
48         my $flesh = {flesh => 1,flesh_fields => { $class => ['owner', 'share_with']}};
49
50         my $meth = "search_reporter_${type}_folder";
51         my $fs = $e->$meth( [{ owner => $e->requestor->id }, $flesh] );
52
53         my @orgs;
54         my $o = $U->storagereq(
55                 'open-ils.storage.actor.org_unit.full_path.atomic', $e->requestor->ws_ou);
56         push( @orgs, $_->id ) for @$o;
57
58         my $fs2 = $e->$meth(
59                 [
60                         {
61                                 shared => 't', 
62                                 share_with => \@orgs, 
63                                 owner => { '!=' => $e->requestor->id } 
64                         }, 
65                         $flesh
66                 ]
67         );
68         push( @$fs, @$fs2);
69         return $fs;
70 }
71
72
73
74 __PACKAGE__->register_method(
75         api_name => 'open-ils.reporter.folder_data.retrieve',
76         method => 'retrieve_folder_data'
77 );
78
79 sub retrieve_folder_data {
80         my( $self, $conn, $auth, $type, $folderid, $limit ) = @_;
81         my $e = new_rstore_editor(authtoken=>$auth);
82         return $e->event unless $e->checkauth;
83         return $e->event unless $e->allowed('RUN_REPORTS');
84         my $meth = "search_reporter_${type}";
85         my $class = 'rr';
86         $class = 'rt' if $type eq 'template';
87         my $flesh = {
88                 flesh => 1,
89                 flesh_fields => { $class => ['owner']}, 
90                 order_by => { $class => 'create_time DESC'} 
91         };
92         $flesh->{limit} = $limit if $limit;
93         return $e->$meth([{ folder => $folderid }, $flesh]); 
94 }
95
96 __PACKAGE__->register_method(
97         api_name => 'open-ils.reporter.schedule.retrieve_by_folder',
98         method => 'retrieve_schedules');
99 sub retrieve_schedules {
100         my( $self, $conn, $auth, $folderId, $limit, $complete ) = @_;
101         my $e = new_rstore_editor(authtoken=>$auth);
102         return $e->event unless $e->checkauth;
103         return $e->event unless $e->allowed('RUN_REPORTS');
104
105         my $search = { folder => $folderId };
106         my $query = [
107                 { folder => $folderId },
108                 { 
109                         order_by => { rs => 'run_time DESC' } ,
110                         flesh => 1,
111                         flesh_fields => { rs => ['report'] }
112                 }
113         ];
114
115         $query->[1]->{limit} = $limit if $limit;
116         $query->[0]->{complete_time} = undef unless $complete;
117         $query->[0]->{complete_time} = { '!=' => undef } if $complete;
118
119         return $e->search_reporter_schedule($query);
120 }
121
122 __PACKAGE__->register_method(
123         api_name => 'open-ils.reporter.schedule.retrieve',
124         method => 'retrieve_schedules');
125 sub retrieve_schedule {
126         my( $self, $conn, $auth, $sched_id ) = @_;
127         my $e = new_rstore_editor(authtoken=>$auth);
128         return $e->event unless $e->checkauth;
129         return $e->event unless $e->allowed('RUN_REPORTS');
130         my $s = $e->retrieve_reporter_schedule($sched_id)
131                 or return $e->event;
132         return $s;
133 }
134
135
136 __PACKAGE__->register_method(
137         api_name => 'open-ils.reporter.template.create',
138         method => 'create_template');
139 sub create_template {
140         my( $self, $conn, $auth, $template ) = @_;
141         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
142         return $e->die_event unless $e->checkauth;
143         return $e->die_event unless $e->allowed('RUN_REPORTS');
144         $template->owner($e->requestor->id);
145
146         my $existing = $e->search_reporter_template( {owner=>$template->owner, 
147                         folder=>$template->folder, name=>$template->name},{idlist=>1});
148         return OpenILS::Event->new('REPORT_TEMPLATE_EXISTS') if @$existing;
149
150         my $tmpl = $e->create_reporter_template($template)
151                 or return $e->die_event;
152         $e->commit;
153         return $tmpl;
154 }
155
156
157
158         
159
160 __PACKAGE__->register_method(
161         api_name => 'open-ils.reporter.report.create',
162         method => 'create_report');
163 sub create_report {
164         my( $self, $conn, $auth, $report, $schedule ) = @_;
165         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
166         return $e->die_event unless $e->checkauth;
167         return $e->die_event unless $e->allowed('RUN_REPORTS');
168         $report->owner($e->requestor->id);
169
170         my $existing = $e->search_reporter_report( {owner=>$report->owner, 
171                         folder=>$report->folder, name=>$report->name},{idlist=>1});
172         return OpenILS::Event->new('REPORT_REPORT_EXISTS') if @$existing;
173
174         my $rpt = $e->create_reporter_report($report)
175                 or return $e->die_event;
176         $schedule->report($rpt->id);
177         $schedule->runner($e->requestor->id);
178         $e->create_reporter_schedule($schedule) or return $e->die_event;
179         $e->commit;
180         return $rpt;
181 }
182
183
184 __PACKAGE__->register_method(
185         api_name => 'open-ils.scheduleer.schedule.create',
186         method => 'create_schedule');
187 sub create_schedule {
188         my( $self, $conn, $auth, $schedule ) = @_;
189         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
190         return $e->die_event unless $e->checkauth;
191         return $e->die_event unless $e->allowed('RUN_REPORTS');
192         my $sched = $e->create_reporter_schedule($schedule)
193                 or return $e->die_event;
194         $e->commit;
195         return $sched;
196 }
197
198 __PACKAGE__->register_method(
199         api_name => 'open-ils.reporter.template.retrieve',
200         method => 'retrieve_template');
201 sub retrieve_template {
202         my( $self, $conn, $auth, $id ) = @_;
203         my $e = new_rstore_editor(authtoken=>$auth);
204         return $e->event unless $e->checkauth;
205         return $e->event unless $e->allowed('RUN_REPORTS');
206         my $t = $e->retrieve_reporter_template($id) 
207                 or return $e->event;
208         return $t;
209 }
210
211
212 __PACKAGE__->register_method(
213         api_name => 'open-ils.reporter.report.retrieve',
214         method => 'retrieve_report');
215 sub retrieve_report {
216         my( $self, $conn, $auth, $id ) = @_;
217         my $e = new_rstore_editor(authtoken=>$auth);
218         return $e->event unless $e->checkauth;
219         return $e->event unless $e->allowed('RUN_REPORTS');
220         my $r = $e->retrieve_reporter_report($id) 
221                 or return $e->event;
222         return $r;
223 }
224
225
226 __PACKAGE__->register_method(
227         api_name => 'open-ils.reporter.template.update',
228         method => 'update_template');
229 sub update_template {
230         my( $self, $conn, $auth, $tmpl ) = @_;
231         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
232         return $e->die_event unless $e->checkauth;
233         return $e->die_event unless $e->allowed('RUN_REPORTS');
234         my $t = $e->retrieve_reporter_template($tmpl->id)
235                 or return $e->die_event;
236         return 0 if $t->owner ne $e->requestor->id;
237         $e->update_reporter_template($tmpl)
238                 or return $e->die_event;
239         $e->commit;
240         return 1;
241 }
242
243
244 __PACKAGE__->register_method(
245         api_name => 'open-ils.reporter.report.update',
246         method => 'update_report');
247 sub update_report {
248         my( $self, $conn, $auth, $report ) = @_;
249         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
250         return $e->die_event unless $e->checkauth;
251         return $e->die_event unless $e->allowed('RUN_REPORTS');
252         my $r = $e->retrieve_reporter_report($report->id)
253                 or return $e->die_event;
254         if( $r->owner ne $e->requestor->id ) {
255                 $e->rollback;
256                 return 0;
257         }
258         $e->update_reporter_report($report)
259                 or return $e->die_event;
260         $e->commit;
261         return 1;
262 }
263
264
265 __PACKAGE__->register_method(
266         api_name => 'open-ils.reporter.schedule.update',
267         method => 'update_schedule');
268 sub update_schedule {
269         my( $self, $conn, $auth, $schedule ) = @_;
270         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
271         return $e->die_event unless $e->checkauth;
272         return $e->die_event unless $e->allowed('RUN_REPORTS');
273         my $s = $e->retrieve_reporter_schedule($schedule->id)
274                 or return $e->die_event;
275         my $r = $e->retrieve_reporter_report($s->report)
276                 or return $e->die_event;
277         if( $r->owner ne $e->requestor->id ) {
278                 $e->rollback;
279                 return 0;
280         }
281         $e->update_reporter_schedule($schedule)
282                 or return $e->die_event;
283         $e->commit;
284         return 1;
285 }
286
287
288 __PACKAGE__->register_method(
289         api_name => 'open-ils.reporter.folder.update',
290         method => 'update_folder');
291 sub update_folder {
292         my( $self, $conn, $auth, $type, $folder ) = @_;
293         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
294         return $e->die_event unless $e->checkauth;
295         return $e->die_event unless $e->allowed('RUN_REPORTS');
296         my $meth = "retrieve_reporter_${type}_folder";
297         my $f = $e->$meth($folder->id) or return $e->die_event;
298         return 0 if $f->owner ne $e->requestor->id;
299         $meth = "update_reporter_${type}_folder";
300         $e->$meth($folder) or return $e->die_event;
301         $e->commit;
302         return 1;
303 }
304
305
306 __PACKAGE__->register_method(
307         api_name => 'open-ils.reporter.folder.delete',
308         method => 'delete_folder');
309 sub delete_folder {
310         my( $self, $conn, $auth, $type, $folderId ) = @_;
311         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
312         return $e->die_event unless $e->checkauth;
313         return $e->die_event unless $e->allowed('RUN_REPORTS');
314         my $meth = "retrieve_reporter_${type}_folder";
315         my $f = $e->$meth($folderId) or return $e->die_event;
316         return 0 if $f->owner ne $e->requestor->id;
317         $meth = "delete_reporter_${type}_folder";
318         $e->$meth($f) or return $e->die_event;
319         $e->commit;
320         return 1;
321 }
322
323
324 __PACKAGE__->register_method(
325         api_name => 'open-ils.reporter.template.delete',
326         method => 'delete_template');
327 sub delete_template {
328         my( $self, $conn, $auth, $templateId ) = @_;
329         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
330         return $e->die_event unless $e->checkauth;
331         return $e->die_event unless $e->allowed('RUN_REPORTS');
332
333         my $t = $e->retrieve_reporter_template($templateId)
334                 or return $e->die_event;
335         return 0 if $t->owner ne $e->requestor->id;
336         $e->delete_reporter_template($t) or return $e->die_event;
337         $e->commit;
338         return 1;
339 }
340
341
342
343 __PACKAGE__->register_method(
344         api_name => 'open-ils.reporter.template.delete.cascade',
345         method => 'cascade_delete_template');
346
347 #__PACKAGE__->register_method(
348 #       api_name => 'open-ils.reporter.template.delete.cascade.force',
349 #       method => 'cascade_delete_template');
350
351 sub cascade_delete_template {
352         my( $self, $conn, $auth, $templateId ) = @_;
353
354         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
355         return $e->die_event unless $e->checkauth;
356         return $e->die_event unless $e->allowed('RUN_REPORTS');
357
358     my $ret = cascade_delete_template_impl(
359         $e, $e->requestor->id, $templateId, ($self->api_name =~ /force/o) );
360     return $ret if ref $ret; # some fatal event occurred
361
362     $e->rollback if $ret == 0;
363     $e->commit if $ret > 0;
364     return $ret;
365 }
366
367
368 __PACKAGE__->register_method(
369         api_name => 'open-ils.reporter.report.delete.cascade',
370         method => 'cascade_delete_report');
371
372 #__PACKAGE__->register_method(
373 #       api_name => 'open-ils.reporter.report.delete.cascade.force',
374 #       method => 'cascade_delete_report');
375
376 sub cascade_delete_report {
377         my( $self, $conn, $auth, $reportId ) = @_;
378
379         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
380         return $e->die_event unless $e->checkauth;
381         return $e->die_event unless $e->allowed('RUN_REPORTS');
382
383     my $ret = cascade_delete_report_impl($e, $e->requestor->id, $reportId);
384     return $ret if ref $ret; # some fatal event occurred
385
386     $e->rollback if $ret == 0;
387     $e->commit if $ret > 0;
388     return $ret;
389 }
390
391
392 # performs a cascading template delete
393 # returns 2 if all data was deleted
394 # returns 1 if some data was deleted
395 # returns 0 if no data was deleted
396 # returns event on error
397 sub cascade_delete_template_impl {
398     my( $e, $owner, $templateId ) = @_;
399
400     # fetch the template to delete
401     my $template = $e->search_reporter_template(
402         {id=>$templateId, owner=>$owner})->[0] or return 0;
403
404     # fetch he attached report IDs for this  owner
405     my $reports = $e->search_reporter_report(
406         {template=>$templateId, owner=>$owner},{idlist=>1});
407
408     # delete the attached reports
409     my $all_rpts_deleted = 1;
410     for my $r (@$reports) {
411         my $evt = cascade_delete_report_impl($e, $owner, $r);
412         return $evt if ref $evt;
413         $all_rpts_deleted = 0 unless $evt == 2;
414     }
415
416     # fetch all reports attached to this template that
417     # do not belong to $owner.  If there are any, we can't 
418     # delete the template
419     my $alt_reports = $e->search_reporter_report(
420         {template=>$templateId, owner=>{"!=" => $owner}},{idlist=>1});
421
422     # all_rpts_deleted will be false if a report has an 
423     # attached scheduled owned by a different user
424     return 1 if @$alt_reports or not $all_rpts_deleted;
425
426     $e->delete_reporter_template($template) 
427         or return $e->die_event;
428     return 2;
429 }
430
431 # performs a cascading report delete
432 # returns 2 if all data was deleted
433 # returns 1 if some data was deleted
434 # returns 0 if no data was deleted
435 # returns event on error
436 sub cascade_delete_report_impl {
437     my( $e, $owner, $reportId ) = @_;
438
439     # fetch the report to delete
440     my $report = $e->search_reporter_report(
441         {id=>$reportId, owner=>$owner})->[0] or return 0;
442
443     # fetch the attached schedule IDs for this owner
444     my $scheds = $e->search_reporter_schedule(
445         {report=>$reportId, runner=>$owner},{idlist=>1});
446
447     # delete the attached schedules
448     for my $sched (@$scheds) {
449         my $evt = delete_schedule_impl($e, $sched);
450         return $evt if $evt;
451     }
452
453     # fetch all schedules attached to this report that
454     # do not belong to $owner.  If there are any, we can't 
455     # delete the report
456     my $alt_scheds = $e->search_reporter_schedule(
457         {report=>$reportId, runner=>{"!=" => $owner}},{idlist=>1});
458
459     return 1 if @$alt_scheds;
460
461     $e->delete_reporter_report($report) 
462         or return $e->die_event;
463
464     return 2;
465 }
466
467
468 # deletes the requested schedule
469 # returns undef on success, event on error
470 sub delete_schedule_impl {
471     my( $e, $schedId ) = @_;
472     my $s = $e->retrieve_reporter_schedule($schedId)
473         or return $e->die_event;
474     $e->delete_reporter_schedule($s) or return $e->die_event;
475     return undef;
476 }
477
478
479
480
481 __PACKAGE__->register_method(
482         api_name => 'open-ils.reporter.report.delete',
483         method => 'delete_report');
484 sub delete_report {
485         my( $self, $conn, $auth, $reportId ) = @_;
486         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
487         return $e->die_event unless $e->checkauth;
488         return $e->die_event unless $e->allowed('RUN_REPORTS');
489
490         my $t = $e->retrieve_reporter_report($reportId)
491                 or return $e->die_event;
492         return 0 if $t->owner ne $e->requestor->id;
493         $e->delete_reporter_report($t) or return $e->die_event;
494         $e->commit;
495         return 1;
496 }
497
498
499 __PACKAGE__->register_method(
500         api_name => 'open-ils.reporter.schedule.delete',
501         method => 'delete_schedule');
502 sub delete_schedule {
503         my( $self, $conn, $auth, $scheduleId ) = @_;
504         my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
505         return $e->die_event unless $e->checkauth;
506         return $e->die_event unless $e->allowed('RUN_REPORTS');
507
508         my $t = $e->retrieve_reporter_schedule($scheduleId)
509                 or return $e->die_event;
510         return 0 if $t->runner ne $e->requestor->id;
511         $e->delete_reporter_schedule($t) or return $e->die_event;
512         $e->commit;
513         return 1;
514 }
515
516
517 __PACKAGE__->register_method(
518         api_name => 'open-ils.reporter.template_has_reports',
519         method => 'has_reports');
520 sub has_reports {
521         my( $self, $conn, $auth, $templateId ) = @_;
522         my $e = new_rstore_editor(authtoken=>$auth);
523         return $e->die_event unless $e->checkauth;
524         return $e->die_event unless $e->allowed('RUN_REPORTS');
525         my $rpts = $e->search_reporter_report({template=>$templateId},{idlist=>1});
526         return 1 if @$rpts;
527         return 0;
528 }
529
530 __PACKAGE__->register_method(
531         api_name => 'open-ils.reporter.report_has_output',
532         method => 'has_output');
533 sub has_output {
534         my( $self, $conn, $auth, $reportId ) = @_;
535         my $e = new_rstore_editor(authtoken=>$auth);
536         return $e->die_event unless $e->checkauth;
537         return $e->die_event unless $e->allowed('RUN_REPORTS');
538         my $outs = $e->search_reporter_schedule({report=>$reportId},{idlist=>1});
539         return 1 if @$outs;
540         return 0;
541 }
542
543
544
545 __PACKAGE__->register_method(
546         method => 'org_full_path',
547         api_name => 'open-ils.reporter.org_unit.full_path');
548
549 sub org_full_path {
550         my( $self, $conn, $orgid ) = @_;
551         return $U->storagereq(
552                 'open-ils.storage.actor.org_unit.full_path.atomic', $orgid );
553 }
554
555
556
557
558 __PACKAGE__->register_method(
559         method => 'magic_fetch_all',
560         api_name => 'open-ils.reporter.magic_fetch');
561 sub magic_fetch_all {
562         my( $self, $conn, $auth, $args ) = @_;
563         my $e = new_editor(authtoken => $auth);
564         return $e->event unless $e->checkauth;
565         return $e->event unless $e->allowed('RUN_REPORTS');
566
567         my $hint = $$args{hint};
568         my $org_col = $$args{org_column};
569         my $orgs = $$args{org};
570
571 #       if ($orgs && !$$args{no_fetch}) {
572 #               ($orgs) = $self
573 #                               ->method_lookup( 'open-ils.reporter.org_unit.full_path' )
574 #                               ->run( @$orgs );
575 #               $orgs = [ map {$_->id} @$orgs ];
576 #       }
577
578         # Find the class the iplements the given hint
579         my ($class) = grep { 
580                 $Fieldmapper::fieldmap->{$_}{hint} eq $hint } Fieldmapper->classes;
581
582         return undef unless $class->Selector;
583
584         $class =~ s/Fieldmapper:://og;
585         $class =~ s/::/_/og;
586         
587         my $method;
588         my $margs;
589
590         if( $org_col ) {
591                 $method = "search_$class";
592                 $margs = { $org_col => $orgs };
593         } else {
594                 $method = "retrieve_all_$class";
595         }
596
597         $logger->info("reporter.magic_fetch => $method");
598
599         return $e->$method($margs);
600 }
601
602
603 1;