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";
12 __PACKAGE__->register_method(
13 api_name => 'open-ils.reporter.folder.create',
14 method => 'create_folder'
18 my( $self, $conn, $auth, $type, $folder ) = @_;
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'));
25 return 0 if $folder->owner ne $e->requestor->id;
27 $folder->owner($e->requestor->id);
28 my $meth = "create_reporter_${type}_folder";
29 $e->$meth($folder) or return $e->die_event;
36 __PACKAGE__->register_method(
37 api_name => 'open-ils.reporter.report.exists',
38 method => 'report_exists',
40 Returns 1 if a report with the given name and folder already exists.
45 my( $self, $conn, $auth, $report ) = @_;
47 my $e = new_rstore_editor(authtoken=>$auth);
48 return $e->event unless $e->checkauth;
49 return $e->event unless $e->allowed('RUN_REPORTS');
51 my $existing = $e->search_reporter_report(
52 {folder=>$report->folder, name=>$report->name});
53 return 1 if @$existing;
58 __PACKAGE__->register_method(
59 api_name => 'open-ils.reporter.folder.visible.retrieve',
60 method => 'retrieve_visible_folders'
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']);
70 return $e->event unless $e->allowed('RUN_REPORTS');
74 $class = 'rtf' if $type eq 'template';
75 $class = 'rof' if $type eq 'output';
78 flesh_fields => { $class => ['owner', 'share_with']},
79 order_by => { $class => 'name ASC'}
82 my $meth = "search_reporter_${type}_folder";
83 my $fs = $e->$meth( [{ owner => $e->requestor->id }, $flesh] );
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;
95 owner => { '!=' => $e->requestor->id }
106 __PACKAGE__->register_method(
107 api_name => 'open-ils.reporter.folder_data.retrieve',
108 method => 'retrieve_folder_data'
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']);
118 return $e->event unless $e->allowed('RUN_REPORTS');
120 my $meth = "search_reporter_${type}";
122 $class = 'rt' if $type eq 'template';
125 flesh_fields => { $class => ['owner']},
126 order_by => { $class => 'create_time DESC'}
128 $flesh->{limit} = $limit if $limit;
129 return $e->$meth([{ folder => $folderid }, $flesh]);
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']);
141 my $search = { folder => $folderId };
143 { folder => $folderId },
145 order_by => { rs => 'run_time DESC' } ,
147 flesh_fields => { rs => ['report'] }
151 $query->[1]->{limit} = $limit if $limit;
152 $query->[0]->{complete_time} = undef unless $complete;
153 $query->[0]->{complete_time} = { '!=' => undef } if $complete;
155 return $e->search_reporter_schedule($query);
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)
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);
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;
187 my $tmpl = $e->create_reporter_template($template)
188 or return $e->die_event;
197 __PACKAGE__->register_method(
198 api_name => 'open-ils.reporter.report.create',
199 method => '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);
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;
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;
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;
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)
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)
262 __PACKAGE__->register_method(
263 api_name => 'open-ils.reporter.report.fleshed.retrieve',
264 method => 'retrieve_fleshed_report',
266 desc => q/Returns report, fleshed with template, template.owner
267 and schedules. Fleshes report.runs() as a single-item array
268 containing the most recently created reporter.schedule./
271 sub retrieve_fleshed_report {
272 my( $self, $conn, $auth, $id, $options ) = @_;
275 my $e = new_rstore_editor(authtoken=>$auth);
276 return $e->event unless $e->checkauth;
277 return $e->event unless $e->allowed(['RUN_REPORTS','VIEW_REPORT_OUTPUT']);
278 my $r = $e->retrieve_reporter_report([
285 }]) or return $e->event;
287 my $output = $e->search_reporter_schedule([
289 {limit => 1, order_by => {rs => 'run_time DESC'}}
300 __PACKAGE__->register_method(
301 api_name => 'open-ils.reporter.template.update',
302 method => 'update_template');
303 sub update_template {
304 my( $self, $conn, $auth, $tmpl ) = @_;
305 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
306 return $e->die_event unless $e->checkauth;
307 return $e->die_event unless $e->allowed('RUN_REPORTS');
308 return $e->die_event unless $e->allowed('CREATE_REPORT_TEMPLATE');
309 my $t = $e->retrieve_reporter_template($tmpl->id)
310 or return $e->die_event;
311 return 0 if $t->owner ne $e->requestor->id;
312 $e->update_reporter_template($tmpl)
313 or return $e->die_event;
319 __PACKAGE__->register_method(
320 api_name => 'open-ils.reporter.report.update',
321 method => 'update_report');
323 my( $self, $conn, $auth, $report ) = @_;
324 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
325 return $e->die_event unless $e->checkauth;
326 return $e->die_event unless $e->allowed('RUN_REPORTS');
327 my $r = $e->retrieve_reporter_report($report->id)
328 or return $e->die_event;
329 if( $r->owner ne $e->requestor->id ) {
333 $e->update_reporter_report($report)
334 or return $e->die_event;
340 __PACKAGE__->register_method(
341 api_name => 'open-ils.reporter.schedule.update',
342 method => 'update_schedule');
343 sub update_schedule {
344 my( $self, $conn, $auth, $schedule ) = @_;
345 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
346 return $e->die_event unless $e->checkauth;
347 return $e->die_event unless $e->allowed('RUN_REPORTS');
348 my $s = $e->retrieve_reporter_schedule($schedule->id)
349 or return $e->die_event;
350 my $r = $e->retrieve_reporter_report($s->report)
351 or return $e->die_event;
352 if( $r->owner ne $e->requestor->id ) {
356 $e->update_reporter_schedule($schedule)
357 or return $e->die_event;
363 __PACKAGE__->register_method(
364 api_name => 'open-ils.reporter.folder.update',
365 method => 'update_folder');
367 my( $self, $conn, $auth, $type, $folder ) = @_;
368 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
369 return $e->die_event unless $e->checkauth;
370 return $e->die_event unless $e->allowed('RUN_REPORTS');
371 my $meth = "retrieve_reporter_${type}_folder";
372 my $f = $e->$meth($folder->id) or return $e->die_event;
373 return 0 if $f->owner ne $e->requestor->id;
374 $meth = "update_reporter_${type}_folder";
375 $e->$meth($folder) or return $e->die_event;
381 __PACKAGE__->register_method(
382 api_name => 'open-ils.reporter.folder.delete',
383 method => 'delete_folder');
385 my( $self, $conn, $auth, $type, $folderId ) = @_;
386 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
387 return $e->die_event unless $e->checkauth;
388 return $e->die_event unless $e->allowed('RUN_REPORTS');
389 my $meth = "retrieve_reporter_${type}_folder";
390 my $f = $e->$meth($folderId) or return $e->die_event;
391 return 0 if $f->owner ne $e->requestor->id;
392 $meth = "delete_reporter_${type}_folder";
393 $e->$meth($f) or return $e->die_event;
399 __PACKAGE__->register_method(
400 api_name => 'open-ils.reporter.template.delete',
401 method => 'delete_template');
402 sub delete_template {
403 my( $self, $conn, $auth, $templateId ) = @_;
404 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
405 return $e->die_event unless $e->checkauth;
406 return $e->die_event unless $e->allowed('RUN_REPORTS');
408 my $t = $e->retrieve_reporter_template($templateId)
409 or return $e->die_event;
410 return 0 if $t->owner ne $e->requestor->id;
411 $e->delete_reporter_template($t) or return $e->die_event;
418 __PACKAGE__->register_method(
419 api_name => 'open-ils.reporter.template.delete.cascade',
420 method => 'cascade_delete_template');
422 #__PACKAGE__->register_method(
423 # api_name => 'open-ils.reporter.template.delete.cascade.force',
424 # method => 'cascade_delete_template');
426 sub cascade_delete_template {
427 my( $self, $conn, $auth, $templateId ) = @_;
429 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
430 return $e->die_event unless $e->checkauth;
431 return $e->die_event unless $e->allowed('RUN_REPORTS');
433 my $ret = cascade_delete_template_impl(
434 $e, $e->requestor->id, $templateId, ($self->api_name =~ /force/o) );
435 return $ret if ref $ret; # some fatal event occurred
437 $e->rollback if $ret == 0;
438 $e->commit if $ret > 0;
443 __PACKAGE__->register_method(
444 api_name => 'open-ils.reporter.report.delete.cascade',
445 method => 'cascade_delete_report');
447 #__PACKAGE__->register_method(
448 # api_name => 'open-ils.reporter.report.delete.cascade.force',
449 # method => 'cascade_delete_report');
451 sub cascade_delete_report {
452 my( $self, $conn, $auth, $reportId ) = @_;
454 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
455 return $e->die_event unless $e->checkauth;
456 return $e->die_event unless $e->allowed('RUN_REPORTS');
458 my $ret = cascade_delete_report_impl($e, $e->requestor->id, $reportId);
459 return $ret if ref $ret; # some fatal event occurred
461 $e->rollback if $ret == 0;
462 $e->commit if $ret > 0;
467 # performs a cascading template delete
468 # returns 2 if all data was deleted
469 # returns 1 if some data was deleted
470 # returns 0 if no data was deleted
471 # returns event on error
472 sub cascade_delete_template_impl {
473 my( $e, $owner, $templateId ) = @_;
475 # fetch the template to delete
476 my $template = $e->search_reporter_template(
477 {id=>$templateId, owner=>$owner})->[0] or return 0;
479 # fetch he attached report IDs for this owner
480 my $reports = $e->search_reporter_report(
481 {template=>$templateId, owner=>$owner},{idlist=>1});
483 # delete the attached reports
484 my $all_rpts_deleted = 1;
485 for my $r (@$reports) {
486 my $evt = cascade_delete_report_impl($e, $owner, $r);
487 return $evt if ref $evt;
488 $all_rpts_deleted = 0 unless $evt == 2;
491 # fetch all reports attached to this template that
492 # do not belong to $owner. If there are any, we can't
493 # delete the template
494 my $alt_reports = $e->search_reporter_report(
495 {template=>$templateId, owner=>{"!=" => $owner}},{idlist=>1});
497 # all_rpts_deleted will be false if a report has an
498 # attached scheduled owned by a different user
499 return 1 if @$alt_reports or not $all_rpts_deleted;
501 $e->delete_reporter_template($template)
502 or return $e->die_event;
506 # performs a cascading report delete
507 # returns 2 if all data was deleted
508 # returns 1 if some data was deleted
509 # returns 0 if no data was deleted
510 # returns event on error
511 sub cascade_delete_report_impl {
512 my( $e, $owner, $reportId ) = @_;
514 # fetch the report to delete
515 my $report = $e->search_reporter_report(
516 {id=>$reportId, owner=>$owner})->[0] or return 0;
518 # fetch the attached schedule IDs for this owner
519 my $scheds = $e->search_reporter_schedule(
520 {report=>$reportId, runner=>$owner},{idlist=>1});
522 # delete the attached schedules
523 for my $sched (@$scheds) {
524 my $evt = delete_schedule_impl($e, $sched);
528 # fetch all schedules attached to this report that
529 # do not belong to $owner. If there are any, we can't
531 my $alt_scheds = $e->search_reporter_schedule(
532 {report=>$reportId, runner=>{"!=" => $owner}},{idlist=>1});
534 return 1 if @$alt_scheds;
536 $e->delete_reporter_report($report)
537 or return $e->die_event;
543 # deletes the requested schedule
544 # returns undef on success, event on error
545 sub delete_schedule_impl {
546 my( $e, $schedId ) = @_;
547 my $s = $e->retrieve_reporter_schedule($schedId)
548 or return $e->die_event;
549 $e->delete_reporter_schedule($s) or return $e->die_event;
556 __PACKAGE__->register_method(
557 api_name => 'open-ils.reporter.report.delete',
558 method => 'delete_report');
560 my( $self, $conn, $auth, $reportId ) = @_;
561 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
562 return $e->die_event unless $e->checkauth;
563 return $e->die_event unless $e->allowed('RUN_REPORTS');
565 my $t = $e->retrieve_reporter_report($reportId)
566 or return $e->die_event;
567 return 0 if $t->owner ne $e->requestor->id;
568 $e->delete_reporter_report($t) or return $e->die_event;
574 __PACKAGE__->register_method(
575 api_name => 'open-ils.reporter.schedule.delete',
576 method => 'delete_schedule');
577 sub delete_schedule {
578 my( $self, $conn, $auth, $scheduleId ) = @_;
579 my $e = new_rstore_editor(authtoken=>$auth, xact=>1);
580 return $e->die_event unless $e->checkauth;
581 return $e->die_event unless $e->allowed('RUN_REPORTS');
583 my $t = $e->retrieve_reporter_schedule($scheduleId)
584 or return $e->die_event;
585 return 0 if $t->runner ne $e->requestor->id;
586 $e->delete_reporter_schedule($t) or return $e->die_event;
592 __PACKAGE__->register_method(
593 api_name => 'open-ils.reporter.template_has_reports',
594 method => 'has_reports');
596 my( $self, $conn, $auth, $templateId ) = @_;
597 my $e = new_rstore_editor(authtoken=>$auth);
598 return $e->die_event unless $e->checkauth;
599 return $e->die_event unless $e->allowed('RUN_REPORTS');
600 my $rpts = $e->search_reporter_report({template=>$templateId},{idlist=>1});
605 __PACKAGE__->register_method(
606 api_name => 'open-ils.reporter.report_has_output',
607 method => 'has_output');
609 my( $self, $conn, $auth, $reportId ) = @_;
610 my $e = new_rstore_editor(authtoken=>$auth);
611 return $e->die_event unless $e->checkauth;
612 return $e->die_event unless $e->allowed('RUN_REPORTS');
613 my $outs = $e->search_reporter_schedule({report=>$reportId},{idlist=>1});
620 __PACKAGE__->register_method(
621 method => 'org_full_path',
622 api_name => 'open-ils.reporter.org_unit.full_path');
625 my( $self, $conn, $orgid ) = @_;
626 return $U->storagereq(
627 'open-ils.storage.actor.org_unit.full_path.atomic', $orgid );
633 __PACKAGE__->register_method(
634 method => 'magic_fetch_all',
635 api_name => 'open-ils.reporter.magic_fetch');
636 sub magic_fetch_all {
637 my( $self, $conn, $auth, $args ) = @_;
638 my $e = new_editor(authtoken => $auth);
639 return $e->event unless $e->checkauth;
640 return $e->event unless $e->allowed('RUN_REPORTS');
642 my $hint = $$args{hint};
643 my $org_col = $$args{org_column};
644 my $orgs = $$args{org};
646 # if ($orgs && !$$args{no_fetch}) {
648 # ->method_lookup( 'open-ils.reporter.org_unit.full_path' )
650 # $orgs = [ map {$_->id} @$orgs ];
653 # Find the class the iplements the given hint
655 $Fieldmapper::fieldmap->{$_}{hint} eq $hint } Fieldmapper->classes;
657 return undef unless $class->Selector;
659 $class =~ s/Fieldmapper:://og;
666 $method = "search_$class";
667 $margs = { $org_col => $orgs };
669 $method = "retrieve_all_$class";
672 $logger->info("reporter.magic_fetch => $method");
674 return $e->$method($margs);