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