View | Details | Raw Unified | Return to bug 16631
Collapse All | Expand All

(-)a/C4/Reports/Guided.pm (-1 / +46 lines)
Lines 881-887 sub get_saved_reports { Link Here
881
881
882
    my $result = $dbh->selectall_arrayref( $query, { Slice => {} }, @args );
882
    my $result = $dbh->selectall_arrayref( $query, { Slice => {} }, @args );
883
883
884
    return $result;
884
    my $limit_pref_enabled = C4::Context->preference('LimitReportsByBranch');
885
886
    return $result unless $limit_pref_enabled;
887
888
    # Preference enabled AND showing all: attach library limits metadata, but do not filter
889
    if ( $filter->{show_all_reports} ) {
890
        foreach my $report (@$result) {
891
            my $report_obj = Koha::Reports->find( $report->{id} );
892
            if ($report_obj) {
893
                my $limits_rs = $report_obj->get_library_limits;
894
                if ($limits_rs) {
895
                    my @branches = map { $_->branchcode } $limits_rs->as_list;
896
                    $report->{library_limits} = \@branches;
897
                } else {
898
                    $report->{library_limits} = [];
899
                }
900
            } else {
901
                $report->{library_limits} = [];
902
            }
903
        }
904
        return $result;
905
    }
906
907
    # Preference enabled AND not showing all: apply library limits filtering
908
    my $limited_reports = Koha::Reports->search_with_library_limits( {}, {}, C4::Context::mybranch() );
909
    my %allowed         = map  { $_->{id} => 1 } @{ $limited_reports->unblessed };
910
    my @limited         = grep { $allowed{ $_->{id} } } @$result;
911
912
    # Attach library limits data for the filtered list
913
    foreach my $report (@limited) {
914
        my $report_obj = Koha::Reports->find( $report->{id} );
915
        if ($report_obj) {
916
            my $limits_rs = $report_obj->get_library_limits;
917
            if ($limits_rs) {
918
                my @branches = map { $_->branchcode } $limits_rs->as_list;
919
                $report->{library_limits} = \@branches;
920
            } else {
921
                $report->{library_limits} = [];
922
            }
923
        } else {
924
            $report->{library_limits} = [];
925
        }
926
    }
927
928
    return \@limited;
929
885
}
930
}
886
931
887
=head2 get_column_type($column)
932
=head2 get_column_type($column)
(-)a/C4/UsageStats.pm (+1 lines)
Lines 314-319 sub _shared_preferences { Link Here
314
        autoMemberNum
314
        autoMemberNum
315
        BorrowerRenewalPeriodBase
315
        BorrowerRenewalPeriodBase
316
        EnableBorrowerFiles
316
        EnableBorrowerFiles
317
        EnableFilteringReports
317
        EnhancedMessagingPreferences
318
        EnhancedMessagingPreferences
318
        ExtendedPatronAttributes
319
        ExtendedPatronAttributes
319
        intranetreadinghistory
320
        intranetreadinghistory
(-)a/Koha/Manual.pm (+1 lines)
Lines 117-122 our $mapping = { Link Here
117
    'admin/preferences#logs'                   => '/logspreferences.html',
117
    'admin/preferences#logs'                   => '/logspreferences.html',
118
    'admin/preferences#opac'                   => '/opacpreferences.html',
118
    'admin/preferences#opac'                   => '/opacpreferences.html',
119
    'admin/preferences#patrons'                => '/patronspreferences.html',
119
    'admin/preferences#patrons'                => '/patronspreferences.html',
120
    'admin/preferences#reports'                => '/reportspreferences.html',
120
    'admin/preferences#searching'              => '/searchingpreferences.html',
121
    'admin/preferences#searching'              => '/searchingpreferences.html',
121
    'admin/preferences#serials'                => '/serialspreferences.html',
122
    'admin/preferences#serials'                => '/serialspreferences.html',
122
    'admin/preferences#staff_interface'        => '/staffclientpreferences.html',
123
    'admin/preferences#staff_interface'        => '/staffclientpreferences.html',
(-)a/Koha/Report.pm (-1 / +60 lines)
Lines 20-28 use Modern::Perl; Link Here
20
use Koha::Database;
20
use Koha::Database;
21
use Koha::Reports;
21
use Koha::Reports;
22
22
23
use Koha::Object;
24
use Koha::Object::Limit::Library;
25
use Koha::Patrons;
26
use C4::Context;
27
28
use base qw(Koha::Object Koha::Object::Limit::Library);
29
23
#use Koha::DateUtils qw( dt_from_string output_pref );
30
#use Koha::DateUtils qw( dt_from_string output_pref );
24
31
25
use base qw(Koha::Object);
26
#
32
#
27
# FIXME We could only return an error code instead of the arrayref
33
# FIXME We could only return an error code instead of the arrayref
28
# Only 1 error is returned
34
# Only 1 error is returned
Lines 268-271 sub _type { Link Here
268
    return 'SavedSql';
274
    return 'SavedSql';
269
}
275
}
270
276
277
=head3 _library_limits
278
279
Configurable library limits
280
281
=cut
282
283
sub _library_limits {
284
    return {
285
        class   => "ReportsBranch",
286
        id      => "report_id",
287
        library => "branchcode",
288
    };
289
}
290
291
=head3 can_manage_limits
292
293
    my $can = Koha::Report->can_manage_limits($patron);
294
295
Returns true if branch limiting is enabled and the patron can manage report limits (superlibrarian or permission reports => manage_report_limits).
296
297
=cut
298
299
sub can_manage_limits {
300
    my ( $class, $patron ) = @_;
301
    return C4::Context->preference('LimitReportsByBranch')
302
        && ( $patron->is_superlibrarian || $patron->has_permission( { reports => 'manage_report_limits' } ) );
303
}
304
305
=head3 can_access
306
307
    my $allowed = $report->can_access($patron);
308
309
Returns true if the patron may access this report considering branch limits, or if limits are disabled.
310
311
=cut
312
313
sub can_access {
314
    my ( $self, $patron ) = @_;
315
316
    return 1 unless C4::Context->preference('LimitReportsByBranch');
317
318
    return 1 if __PACKAGE__->can_manage_limits($patron);
319
320
    my $limits_rs = $self->get_library_limits;
321
    return 1 unless $limits_rs;
322
323
    my $user_branch = C4::Context::mybranch();
324
    return 0 unless $user_branch;
325
326
    my %allowed = map { $_->branchcode => 1 } $limits_rs->as_list;
327
    return $allowed{$user_branch} ? 1 : 0;
328
}
329
271
1;
330
1;
(-)a/Koha/Reports.pm (-7 / +1 lines)
Lines 21-27 use Koha::Database; Link Here
21
21
22
use Koha::Report;
22
use Koha::Report;
23
23
24
use base qw(Koha::Objects);
24
use base qw(Koha::Objects Koha::Objects::Limit::Library);
25
25
26
=head1 NAME
26
=head1 NAME
27
27
Lines 33-44 Koha::Reports - Koha Report Object set class Link Here
33
33
34
=cut
34
=cut
35
35
36
=head3 _type
37
38
Returns name of corresponding DBIC resultset
39
40
=cut
41
42
sub _type {
36
sub _type {
43
    return 'SavedSql';
37
    return 'SavedSql';
44
}
38
}
(-)a/admin/columns_settings.yml (+3 lines)
Lines 1675-1680 modules: Link Here
1675
              columnname: saved_results
1675
              columnname: saved_results
1676
            -
1676
            -
1677
              columnname: update
1677
              columnname: update
1678
            -
1679
              columnname: library_limits
1680
              is_hidden: 1
1678
            -
1681
            -
1679
              columnname: actions
1682
              columnname: actions
1680
              cannot_be_toggled: 1
1683
              cannot_be_toggled: 1
(-)a/installer/data/mysql/atomicupdate/bug_16631.pl (+39 lines)
Line 0 Link Here
1
use Modern::Perl;
2
use Koha::Installer::Output qw(say_warning say_success say_info);
3
4
return {
5
    bug_number  => "16631",
6
    description => "Add library limits to reports",
7
    up          => sub {
8
        my ($args) = @_;
9
        my ( $dbh, $out ) = @$args{qw(dbh out)};
10
11
        $dbh->do(
12
            q{CREATE TABLE IF NOT EXISTS `reports_branches` (
13
            `report_id` int(11) NOT NULL,
14
            `branchcode` varchar(10) NOT NULL,
15
            KEY `report_id` (`report_id`),
16
            KEY `branchcode` (`branchcode`),
17
            CONSTRAINT `reports_branches_ibfk_1` FOREIGN KEY (`report_id`) REFERENCES `saved_sql` (`id`) ON DELETE CASCADE,
18
            CONSTRAINT `reports_branches_ibfk_2` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE
19
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci}
20
        );
21
22
        say $out "Added new table 'reports_branches'";
23
24
        $dbh->do(
25
            q{INSERT IGNORE INTO systempreferences
26
            (variable,value,options,explanation,type) VALUES ('LimitReportsByBranch', '0', NULL, 'Enable ability for staff to limit report access based on home library.', 'YesNo')}
27
        );
28
29
        say $out "Added new system preference 'LimitReportsByBranch'";
30
31
        $dbh->do(
32
            q{INSERT IGNORE INTO permissions 
33
            (module_bit, code, description) VALUES (16, 'manage_report_limits', 'Manage report limits')}
34
        );
35
36
        say $out "Added new permission 'manage_report_limits'";
37
38
    },
39
};
(-)a/installer/data/mysql/kohastructure.sql (+13 lines)
Lines 5772-5777 CREATE TABLE `saved_reports` ( Link Here
5772
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
5772
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
5773
/*!40101 SET character_set_client = @saved_cs_client */;
5773
/*!40101 SET character_set_client = @saved_cs_client */;
5774
5774
5775
DROP TABLE IF EXISTS `reports_branches`;
5776
/*!40101 SET @saved_cs_client     = @@character_set_client */;
5777
/*!40101 SET character_set_client = utf8mb4 */;
5778
CREATE TABLE `reports_branches` (
5779
  `report_id` int(11) NOT NULL,
5780
  `branchcode` varchar(10) NOT NULL,
5781
  KEY `report_id` (`report_id`),
5782
  KEY `branchcode` (`branchcode`),
5783
  CONSTRAINT `reports_branches_ibfk_1` FOREIGN KEY (`report_id`) REFERENCES `saved_sql` (`id`) ON DELETE CASCADE,
5784
  CONSTRAINT `reports_branches_ibfk_2` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE
5785
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
5786
/*!40101 SET character_set_client = @saved_cs_client */;
5787
5775
--
5788
--
5776
-- Table structure for table `saved_sql`
5789
-- Table structure for table `saved_sql`
5777
--
5790
--
(-)a/installer/data/mysql/mandatory/sysprefs.sql (+1 lines)
Lines 385-390 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
385
('LibraryThingForLibrariesTabbedView','0','','Put LibraryThingForLibraries Content in Tabs.','YesNo'),
385
('LibraryThingForLibrariesTabbedView','0','','Put LibraryThingForLibraries Content in Tabs.','YesNo'),
386
('LibrisKey', '', 'This key must be obtained at http://api.libris.kb.se/. It is unique for the IP of the server.', NULL, 'Free'),
386
('LibrisKey', '', 'This key must be obtained at http://api.libris.kb.se/. It is unique for the IP of the server.', NULL, 'Free'),
387
('LibrisURL', 'http://api.libris.kb.se/bibspell/', 'This it the base URL for the Libris spellchecking API.',NULL,'Free'),
387
('LibrisURL', 'http://api.libris.kb.se/bibspell/', 'This it the base URL for the Libris spellchecking API.',NULL,'Free'),
388
('LimitReportsByBranch', '0', NULL, 'Enable ability for staff to limit report access based on home library.', 'YesNo'),
388
('LinkerConsiderDiacritics', '0', NULL, 'Linker should consider diacritics', 'YesNo'),
389
('LinkerConsiderDiacritics', '0', NULL, 'Linker should consider diacritics', 'YesNo'),
389
('LinkerConsiderThesaurus','0',NULL,'If ON the authority linker will only search for 6XX authorities from the same source as the heading','YesNo'),
390
('LinkerConsiderThesaurus','0',NULL,'If ON the authority linker will only search for 6XX authorities from the same source as the heading','YesNo'),
390
('LinkerKeepStale','0',NULL,'If ON the authority linker will keep existing authority links for headings where it is unable to find a match.','YesNo'),
391
('LinkerKeepStale','0',NULL,'If ON the authority linker will keep existing authority links for headings where it is unable to find a match.','YesNo'),
(-)a/installer/data/mysql/mandatory/userpermissions.sql (+1 lines)
Lines 141-146 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
141
   (16, 'execute_reports', 'Execute SQL reports'),
141
   (16, 'execute_reports', 'Execute SQL reports'),
142
   (16, 'create_reports', 'Create SQL reports'),
142
   (16, 'create_reports', 'Create SQL reports'),
143
   (16, 'delete_reports', 'Delete SQL reports'),
143
   (16, 'delete_reports', 'Delete SQL reports'),
144
   (16, 'manage_report_limits', 'Manage report limits'),
144
   (18, 'manage_courses', 'Add, edit and delete courses'),
145
   (18, 'manage_courses', 'Add, edit and delete courses'),
145
   (18, 'add_reserves', 'Add course reserves'),
146
   (18, 'add_reserves', 'Add course reserves'),
146
   (18, 'delete_reserves', 'Remove course reserves'),
147
   (18, 'delete_reserves', 'Remove course reserves'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc (+3 lines)
Lines 487-492 Link Here
487
    [%- CASE 'execute_reports' -%]
487
    [%- CASE 'execute_reports' -%]
488
        <span class="sub_permission execute_reports_subpermission"> Execute SQL reports </span>
488
        <span class="sub_permission execute_reports_subpermission"> Execute SQL reports </span>
489
        <span class="permissioncode">([% name | html %])</span>
489
        <span class="permissioncode">([% name | html %])</span>
490
    [%- CASE 'manage_report_limits' -%]
491
        <span class="sub_permission manage_report_limits_subpermission"> Manage Report Limits </span>
492
        <span class="permissioncode">([% name | html %])</span>
490
    [%- CASE 'add_reserves' -%]
493
    [%- CASE 'add_reserves' -%]
491
        <span class="sub_permission add_reserves_subpermission"> Add course reserves </span>
494
        <span class="sub_permission add_reserves_subpermission"> Add course reserves </span>
492
        <span class="permissioncode">([% name | html %])</span>
495
        <span class="permissioncode">([% name | html %])</span>
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/prefs-menu.inc (+11 lines)
Lines 165-170 Link Here
165
            </li>
165
            </li>
166
        [% END %]
166
        [% END %]
167
167
168
        [% IF ( reports ) %]
169
            <li class="active">
170
                <a title="Reports" href="/cgi-bin/koha/admin/preferences.pl?tab=reports">Reports</a>
171
                [% PROCESS subtabs %]
172
            </li>
173
        [% ELSE %]
174
            <li>
175
                <a title="Reports" href="/cgi-bin/koha/admin/preferences.pl?tab=reports">Reports</a>
176
            </li>
177
        [% END %]
178
        
168
        [% IF ( searching ) %]
179
        [% IF ( searching ) %]
169
            <li class="active">
180
            <li class="active">
170
                <a title="Searching" href="/cgi-bin/koha/admin/preferences.pl?tab=searching">Searching</a>
181
                <a title="Searching" href="/cgi-bin/koha/admin/preferences.pl?tab=searching">Searching</a>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/reports.pref (+8 lines)
Line 0 Link Here
1
Reports:
2
    Reports Access:
3
     -
4
         - pref: LimitReportsByBranch
5
           choices:
6
               1: Enable
7
               0: Disable
8
         - "limiting report access based on staff home library."
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/guided_reports_start.tt (-4 / +70 lines)
Lines 3-8 Link Here
3
[% USE AuthorisedValues %]
3
[% USE AuthorisedValues %]
4
[% USE KohaDates %]
4
[% USE KohaDates %]
5
[% USE Koha %]
5
[% USE Koha %]
6
[% USE Branches %]
6
[% USE TablesSettings %]
7
[% USE TablesSettings %]
7
[% USE HtmlScrubber %]
8
[% USE HtmlScrubber %]
8
[% USE JSON.Escape %]
9
[% USE JSON.Escape %]
Lines 201-206 Link Here
201
202
202
                [% INCLUDE "reports-toolbar.inc" %]
203
                [% INCLUDE "reports-toolbar.inc" %]
203
204
205
                [% IF access_denied %]
206
                    <div>
207
                        <h1>Access denied</h1>
208
                        <p>This report is restricted and cannot be accessed by the current user.</p>
209
                        [% IF id %]<p>Report ID: [% id | html %]</p>[% END %]
210
                        <p><a class="btn btn-secondary" href="/cgi-bin/koha/reports/guided_reports.pl?op=list">Return to saved reports</a></p>
211
                    </div>
212
                [% END %]
213
204
                [% IF ( start ) %]
214
                [% IF ( start ) %]
205
                    <h1>Guided reports</h1>
215
                    <h1>Guided reports</h1>
206
                    <p>Use the guided reports engine to create non standard reports. This feature aims to provide some middle ground between the built in canned reports and writing custom SQL reports.</p>
216
                    <p>Use the guided reports engine to create non standard reports. This feature aims to provide some middle ground between the built in canned reports and writing custom SQL reports.</p>
Lines 236-242 Link Here
236
                    <h1>Saved reports</h1>
246
                    <h1>Saved reports</h1>
237
                    [% IF ( savedreports ) %]
247
                    [% IF ( savedreports ) %]
238
248
239
                        [% IF ( filters.date || filters.author || filters.keyword ) %]
249
                        [% IF ( filters.date || filters.author || filters.keyword || branch_limit_active ) %]
240
                            <p
250
                            <p
241
                                >Filtered by:
251
                                >Filtered by:
242
                                <span class="filter">
252
                                <span class="filter">
Lines 249-254 Link Here
249
                                    [% IF ( filters.keyword ) %]
259
                                    [% IF ( filters.keyword ) %]
250
                                        <span class="filter_keyword"><strong>Keyword:</strong> [% filters.keyword | html %]</span>
260
                                        <span class="filter_keyword"><strong>Keyword:</strong> [% filters.keyword | html %]</span>
251
                                    [% END %]
261
                                    [% END %]
262
                                    [% IF branch_limit_active %]
263
                                        <span class="filter_show_all"><strong>Show reports:</strong> My branch reports</span>
264
                                    [% END %]
252
                                    <a class="clear_filter" href="/cgi-bin/koha/reports/guided_reports.pl?op=list&clear_filters=1"><i class="fa fa-times" aria-hidden="true"></i> Clear</a>
265
                                    <a class="clear_filter" href="/cgi-bin/koha/reports/guided_reports.pl?op=list&clear_filters=1"><i class="fa fa-times" aria-hidden="true"></i> Clear</a>
253
                                </span>
266
                                </span>
254
                            </p>
267
                            </p>
Lines 309-314 Link Here
309
                                                    [% ELSE %]
322
                                                    [% ELSE %]
310
                                                        <th class="NoVisible">Update</th>
323
                                                        <th class="NoVisible">Update</th>
311
                                                    [% END %]
324
                                                    [% END %]
325
                                                    [% IF ( can_manage_report_limits ) %]
326
                                                        <th>Library limits</th>
327
                                                    [% END %]
312
                                                    <th class="no-sort no-export">Actions</th>
328
                                                    <th class="no-sort no-export">Actions</th>
313
                                                </tr>
329
                                                </tr>
314
                                            </thead>
330
                                            </thead>
Lines 376-381 Link Here
376
                                                                >
392
                                                                >
377
                                                            [% END %]
393
                                                            [% END %]
378
                                                        </td>
394
                                                        </td>
395
                                                        [% IF ( can_manage_report_limits ) %]
396
                                                            <td>
397
                                                                [% IF savedreport.library_limits %]
398
                                                                    [% savedreport.library_limits.join(', ') %]
399
                                                                [% END %]
400
                                                            </td>
401
                                                        [% END %]
379
                                                        <td>
402
                                                        <td>
380
                                                            <div class="btn-group dropup">
403
                                                            <div class="btn-group dropup">
381
                                                                [%# There should be no space between these two buttons, it would render badly %]
404
                                                                [%# There should be no space between these two buttons, it would render badly %]
Lines 455-461 Link Here
455
478
456
                                    <a href="/cgi-bin/koha/reports/guided_reports.pl?op=add_form_sql" class="new btn btn-default"><i class="fa fa-plus" aria-hidden="true"></i> New SQL report</a>
479
                                    <a href="/cgi-bin/koha/reports/guided_reports.pl?op=add_form_sql" class="new btn btn-default"><i class="fa fa-plus" aria-hidden="true"></i> New SQL report</a>
457
480
458
                                    <a href="/cgi-bin/koha/reports/guided_reports.pl?op=list&filter_set=1&filter_keywork=" class="deny btn btn-default"><i class="fa fa-fw fa-times" aria-hidden="true"></i> Cancel filter</a>
481
                                    <a href="/cgi-bin/koha/reports/guided_reports.pl?op=list&filter_set=1&clear_filters=1" class="deny btn btn-default"><i class="fa fa-fw fa-times" aria-hidden="true"></i> Cancel filter</a>
459
                                [% END %]
482
                                [% END %]
460
                            [% ELSE %]
483
                            [% ELSE %]
461
                                <h4>There are no saved reports. </h4>
484
                                <h4>There are no saved reports. </h4>
Lines 850-855 Link Here
850
                            <input type="hidden" name="reportname" value="[% reportname | html %]" />
873
                            <input type="hidden" name="reportname" value="[% reportname | html %]" />
851
                            <input type="hidden" name="group" value="[% group | html %]" />
874
                            <input type="hidden" name="group" value="[% group | html %]" />
852
                            <input type="hidden" name="subgroup" value="[% subgroup | html %]" />
875
                            <input type="hidden" name="subgroup" value="[% subgroup | html %]" />
876
                            <input type="hidden" name="branches" value="[% branches | html %]" />
853
                            <input type="hidden" name="notes" value="[% notes | scrub_html type => 'note' | $raw %]" />
877
                            <input type="hidden" name="notes" value="[% notes | scrub_html type => 'note' | $raw %]" />
854
                            <input type="hidden" name="cache_expiry" value="[% cache_expiry | html %]" />
878
                            <input type="hidden" name="cache_expiry" value="[% cache_expiry | html %]" />
855
                            <input type="hidden" name="cache_expiry_units" value="[% cache_expiry_units | html %]" />
879
                            <input type="hidden" name="cache_expiry_units" value="[% cache_expiry_units | html %]" />
Lines 1434-1440 Link Here
1434
                                <span class="required">Required</span>
1458
                                <span class="required">Required</span>
1435
                            </div>
1459
                            </div>
1436
                        </fieldset>
1460
                        </fieldset>
1437
1461
                        [% IF ( Koha.Preference('LimitReportsByBranch') && ( CAN_user_superlibrarian || CAN_user_reports_manage_report_limits ) ) %]
1462
                            <fieldset class="rows">
1463
                                <legend>Library limitation:</legend>
1464
                                <div
1465
                                    ><label for="library_limitation">Library limitation: </label>
1466
                                    <select id="library_limitation" name="branches" multiple size="10">
1467
                                        [% PROCESS options_for_libraries libraries => Branches.all( selected => report.get_library_limits, unfiltered => 1, do_not_select_my_library => 1 ) %]
1468
                                    </select>
1469
                                    <div class="hint">Limits the use of this report to the selected libraries.</div>
1470
                                </div>
1471
                            </fieldset>
1472
                        [% END %]
1438
                        <fieldset class="action">
1473
                        <fieldset class="action">
1439
                            <input type="hidden" name="op" value="cud-save" />
1474
                            <input type="hidden" name="op" value="cud-save" />
1440
                            <input type="submit" name="submit" class="btn btn-primary" value="Save report" />
1475
                            <input type="submit" name="submit" class="btn btn-primary" value="Save report" />
Lines 1548-1554 Link Here
1548
                            <br />
1583
                            <br />
1549
                            <span class="required" style="margin-left:30px;">Required</span>
1584
                            <span class="required" style="margin-left:30px;">Required</span>
1550
                        </fieldset>
1585
                        </fieldset>
1551
1586
                        [% IF ( Koha.Preference('LimitReportsByBranch') && ( CAN_user_superlibrarian || CAN_user_reports_manage_report_limits ) ) %]
1587
                            <fieldset class="rows">
1588
                                <legend>Library limitation:</legend>
1589
                                <div
1590
                                    ><label for="library_limitation">Library limitation: </label>
1591
                                    <select id="library_limitation" name="branches" multiple size="10">
1592
                                        [% PROCESS options_for_libraries libraries => Branches.all( selected => report.get_library_limits, unfiltered => 1, do_not_select_my_library => 1 ) %]
1593
                                    </select>
1594
                                    <div class="hint">Limits the use of this report to the selected libraries.</div>
1595
                                </div>
1596
                            </fieldset>
1597
                        [% END %]
1552
                        <fieldset class="action">
1598
                        <fieldset class="action">
1553
                            <button class="btn btn-primary" type="submit" name="op" value="cud-update_sql">Update SQL</button>
1599
                            <button class="btn btn-primary" type="submit" name="op" value="cud-update_sql">Update SQL</button>
1554
                            <button class="btn btn-default" type="submit" name="op" value="cud-update_and_run_sql">Update and run SQL</button>
1600
                            <button class="btn btn-default" type="submit" name="op" value="cud-update_and_run_sql">Update and run SQL</button>
Lines 1616-1621 Link Here
1616
                                        <label for="filter_keyword">Keyword:</label>
1662
                                        <label for="filter_keyword">Keyword:</label>
1617
                                        <input type="text" id="filter_keyword" name="filter_keyword" value="[% filters.keyword | html %]" size="16" />
1663
                                        <input type="text" id="filter_keyword" name="filter_keyword" value="[% filters.keyword | html %]" size="16" />
1618
                                    </li>
1664
                                    </li>
1665
                                    <li>
1666
                                        [% IF Koha.Preference('LimitReportsByBranch') %]
1667
                                            [% IF ( CAN_user_superlibrarian || CAN_user_reports_manage_report_limits ) %]
1668
                                                <label for="filter_show_all_reports">Show reports:</label>
1669
                                                <select name="filter_show_all_reports" id="filter_show_all_reports">
1670
                                                    [% IF filters.show_all_reports == "1" %]
1671
                                                        <option value="1" selected="selected">Show all reports</option>
1672
                                                    [% ELSE %]
1673
                                                        <option value="1">Show all reports</option>
1674
                                                    [% END %]
1675
1676
                                                    [% IF filters.show_all_reports == 0 %]
1677
                                                        <option value="0" selected="selected">Show my branch reports</option>
1678
                                                    [% ELSE %]
1679
                                                        <option value="0">Show my branch reports</option>
1680
                                                    [% END %]
1681
                                                </select>
1682
                                            [% END %]
1683
                                        [% END %]
1684
                                    </li>
1619
                                </ol>
1685
                                </ol>
1620
                            </fieldset>
1686
                            </fieldset>
1621
                            <!-- /.brief -->
1687
                            <!-- /.brief -->
(-)a/reports/guided_reports.pl (-248 / +307 lines)
Lines 83-101 my ( $template, $borrowernumber, $cookie ) = get_template_and_user( Link Here
83
my $session_id = $input->cookie('CGISESSID');
83
my $session_id = $input->cookie('CGISESSID');
84
my $session    = $session_id ? get_session($session_id) : undef;
84
my $session    = $session_id ? get_session($session_id) : undef;
85
85
86
$template->param( templates => Koha::Notice::Templates->search( { module => 'report' } ) );
87
88
my $filter;
86
my $filter;
89
if ( $input->param("filter_set") or $input->param('clear_filters') ) {
87
if ( $input->param("filter_set") or $input->param('clear_filters') ) {
90
    $filter = {};
88
    $filter = {};
91
    $filter->{$_} = $input->param("filter_$_") foreach qw/date author keyword group subgroup/;
89
    $filter->{$_} = $input->param("filter_$_") foreach qw/date author keyword show_all_reports group subgroup/;
90
91
    if ( $input->param('clear_filters') ) {
92
        $filter->{show_all_reports} = 1;
93
    }
94
92
    $session->param( 'report_filter', $filter ) if $session;
95
    $session->param( 'report_filter', $filter ) if $session;
93
    $template->param( 'filter_set' => 1 );
96
    $template->param( 'filter_set' => 1 );
94
} elsif ( $session and not $input->param('clear_filters') ) {
97
} elsif ( $session and not $input->param('clear_filters') ) {
95
    $filter = $session->param('report_filter');
98
    $filter = $session->param('report_filter');
96
}
99
}
97
100
98
my @errors = ();
101
my @errors             = ();
102
my %OP_REQUIRES_REPORT = map { $_ => 1 } qw(show edit_form duplicate cud-update_sql cud-update_and_run_sql export run);
103
my $report_id          = $input->param('id');
104
my $report;
105
my $access_blocked;
106
if ( $OP_REQUIRES_REPORT{$op} && $report_id ) {
107
    $report = Koha::Reports->find($report_id);
108
    if ($report) {
109
        my $patron = Koha::Patrons->find($borrowernumber);
110
        unless ( $report->can_access($patron) ) {
111
            $template->param( access_denied => 1, denied_op => $op, id => $report_id );
112
            $access_blocked = 1;
113
        }
114
    } else {
115
        push @errors, { no_sql_for_id => $report_id };
116
    }
117
}
118
119
if ($access_blocked) {
120
    output_html_with_http_headers $input, $cookie, $template->output;
121
    exit;
122
}
123
99
if ( !$op ) {
124
if ( !$op ) {
100
    $template->param( 'start' => 1 );
125
    $template->param( 'start' => 1 );
101
126
Lines 116-262 if ( !$op ) { Link Here
116
    $op = 'list';
141
    $op = 'list';
117
142
118
} elsif ( $op eq 'show' ) {
143
} elsif ( $op eq 'show' ) {
119
144
    if ($report) {
120
    my $id     = $input->param('id');
145
        $template->param(
121
    my $report = Koha::Reports->find($id);
146
            'id'            => $report_id,
122
    $template->param(
147
            'reportname'    => $report->report_name,
123
        'id'            => $id,
148
            'notes'         => $report->notes,
124
        'reportname'    => $report->report_name,
149
            'sql'           => $report->savedsql,
125
        'notes'         => $report->notes,
150
            'showsql'       => 1,
126
        'sql'           => $report->savedsql,
151
            'mana_success'  => scalar $input->param('mana_success'),
127
        'showsql'       => 1,
152
            'mana_id'       => $report->{mana_id},
128
        'mana_success'  => scalar $input->param('mana_success'),
153
            'mana_comments' => $report->{comments}
129
        'mana_id'       => $report->{mana_id},
154
        );
130
        'mana_comments' => $report->{comments}
155
    }
131
    );
132
156
133
} elsif ( $op eq 'edit_form' ) {
157
} elsif ( $op eq 'edit_form' ) {
134
    my $id       = $input->param('id');
158
    if ($report) {
135
    my $report   = Koha::Reports->find($id);
159
        my $group    = $report->report_group;
136
    my $group    = $report->report_group;
160
        my $subgroup = $report->report_subgroup;
137
    my $subgroup = $report->report_subgroup;
161
        my $tables   = get_tables();
138
    my $tables   = get_tables();
162
        $template->param(
139
    $template->param(
163
            'sql'                   => $report->savedsql,
140
        'sql'                   => $report->savedsql,
164
            'reportname'            => $report->report_name,
141
        'reportname'            => $report->report_name,
165
            'groups_with_subgroups' => groups_with_subgroups( $group, $subgroup ),
142
        'groups_with_subgroups' => groups_with_subgroups( $group, $subgroup ),
166
            'notes'                 => $report->notes,
143
        'notes'                 => $report->notes,
167
            'id'                    => $report_id,
144
        'id'                    => $id,
168
            'cache_expiry'          => $report->cache_expiry,
145
        'cache_expiry'          => $report->cache_expiry,
169
            'public'                => $report->public,
146
        'public'                => $report->public,
170
            'usecache'              => $usecache,
147
        'usecache'              => $usecache,
171
            'editsql'               => 1,
148
        'editsql'               => 1,
172
            'mana_id'               => $report->{mana_id},
149
        'mana_id'               => $report->{mana_id},
173
            'mana_comments'         => $report->{comments},
150
        'mana_comments'         => $report->{comments},
174
            'tables'                => $tables,
151
        'tables'                => $tables
175
            'report'                => $report,
152
    );
176
        );
177
    }
153
178
154
} elsif ( $op eq 'cud-update_sql' || $op eq 'cud-update_and_run_sql' ) {
179
} elsif ( $op eq 'cud-update_sql' || $op eq 'cud-update_and_run_sql' ) {
155
    my $id                 = $input->param('id');
180
    if ($report) {
156
    my $sql                = $input->param('sql');
181
        my $id                 = $report_id;
157
    my $reportname         = $input->param('reportname');
182
        my $sql                = $input->param('sql');
158
    my $group              = $input->param('group');
183
        my $reportname         = $input->param('reportname');
159
    my $subgroup           = $input->param('subgroup');
184
        my $group              = $input->param('group');
160
    my $notes              = $input->param('notes');
185
        my $subgroup           = $input->param('subgroup');
161
    my $cache_expiry       = $input->param('cache_expiry');
186
        my $notes              = $input->param('notes');
162
    my $cache_expiry_units = $input->param('cache_expiry_units');
187
        my $cache_expiry       = $input->param('cache_expiry');
163
    my $public             = $input->param('public');
188
        my $cache_expiry_units = $input->param('cache_expiry_units');
164
    my $save_anyway        = $input->param('save_anyway');
189
        my $public             = $input->param('public');
165
    my @errors;
190
        my $save_anyway        = $input->param('save_anyway');
166
    my $tables = get_tables();
191
        my @errors;
192
        my $tables   = get_tables();
193
        my @branches = grep { $_ ne q{} } $input->multi_param('branches');
194
195
        # if we have the units, then we came from creating a report from SQL and thus need to handle converting units
196
        if ($cache_expiry_units) {
197
            if ( $cache_expiry_units eq "minutes" ) {
198
                $cache_expiry *= 60;
199
            } elsif ( $cache_expiry_units eq "hours" ) {
200
                $cache_expiry *= 3600;    # 60 * 60
201
            } elsif ( $cache_expiry_units eq "days" ) {
202
                $cache_expiry *= 86400;    # 60 * 60 * 24
203
            }
204
        }
167
205
168
    # if we have the units, then we came from creating a report from SQL and thus need to handle converting units
206
        # check $cache_expiry isn't too large, Memcached::set requires it to be less than 30 days or it will be treated as if it were an absolute time stamp
169
    if ($cache_expiry_units) {
207
        if ( $cache_expiry >= 2592000 ) {
170
        if ( $cache_expiry_units eq "minutes" ) {
208
            push @errors, { cache_expiry => $cache_expiry };
171
            $cache_expiry *= 60;
172
        } elsif ( $cache_expiry_units eq "hours" ) {
173
            $cache_expiry *= 3600;    # 60 * 60
174
        } elsif ( $cache_expiry_units eq "days" ) {
175
            $cache_expiry *= 86400;    # 60 * 60 * 24
176
        }
209
        }
177
    }
178
210
179
    # check $cache_expiry isn't too large, Memcached::set requires it to be less than 30 days or it will be treated as if it were an absolute time stamp
211
        create_non_existing_group_and_subgroup( $input, $group, $subgroup );
180
    if ( $cache_expiry >= 2592000 ) {
181
        push @errors, { cache_expiry => $cache_expiry };
182
    }
183
212
184
    create_non_existing_group_and_subgroup( $input, $group, $subgroup );
213
        my ( $is_sql_valid, $validation_errors ) = Koha::Report->new( { savedsql => $sql } )->is_sql_valid;
214
        push( @errors, @$validation_errors ) unless $is_sql_valid;
185
215
186
    my ( $is_sql_valid, $validation_errors ) = Koha::Report->new( { savedsql => $sql } )->is_sql_valid;
216
        if (@errors) {
187
    push( @errors, @$validation_errors ) unless $is_sql_valid;
217
            $template->param(
218
                'errors' => \@errors,
219
                'sql'    => $sql,
220
            );
221
        } else {
188
222
189
    if (@errors) {
223
            # Check defined SQL parameters for authorised value validity
190
        $template->param(
224
            my $problematic_authvals = ValidateSQLParameters($sql);
191
            'errors' => \@errors,
192
            'sql'    => $sql,
193
        );
194
    } else {
195
225
196
        # Check defined SQL parameters for authorised value validity
226
            if ( scalar @$problematic_authvals > 0 && not $save_anyway ) {
197
        my $problematic_authvals = ValidateSQLParameters($sql);
198
227
199
        if ( scalar @$problematic_authvals > 0 && not $save_anyway ) {
228
                # There's at least one problematic parameter, report to the
229
                # GUI and provide all user input for further actions
230
                $template->param(
231
                    'id'                   => $id,
232
                    'sql'                  => $sql,
233
                    'reportname'           => $reportname,
234
                    'group'                => $group,
235
                    'subgroup'             => $subgroup,
236
                    'notes'                => $notes,
237
                    'public'               => $public,
238
                    'problematic_authvals' => $problematic_authvals,
239
                    'warn_authval_problem' => 1,
240
                    'phase_update'         => 1,
241
                    'branches'             => @branches,
242
                    'report'               => $report,
243
                );
200
244
201
            # There's at least one problematic parameter, report to the
245
            } else {
202
            # GUI and provide all user input for further actions
203
            $template->param(
204
                'id'                   => $id,
205
                'sql'                  => $sql,
206
                'reportname'           => $reportname,
207
                'group'                => $group,
208
                'subgroup'             => $subgroup,
209
                'notes'                => $notes,
210
                'public'               => $public,
211
                'problematic_authvals' => $problematic_authvals,
212
                'warn_authval_problem' => 1,
213
                'phase_update'         => 1,
214
            );
215
246
216
        } else {
247
                # No params problem found or asked to save anyway
248
                update_sql(
249
                    $id,
250
                    {
251
                        sql          => $sql,
252
                        name         => $reportname,
253
                        group        => $group,
254
                        subgroup     => $subgroup,
255
                        notes        => $notes,
256
                        public       => $public,
257
                        cache_expiry => $cache_expiry,
258
                    }
259
                );
217
260
218
            # No params problem found or asked to save anyway
261
                $report->store;
219
            update_sql(
262
                $report->replace_library_limits( \@branches );
220
                $id,
263
221
                {
264
                my $editsql = 1;
222
                    sql          => $sql,
265
                if ( $op eq 'cud-update_and_run_sql' ) {
223
                    name         => $reportname,
266
                    $editsql = 0;
224
                    group        => $group,
225
                    subgroup     => $subgroup,
226
                    notes        => $notes,
227
                    public       => $public,
228
                    cache_expiry => $cache_expiry,
229
                }
267
                }
230
            );
231
268
232
            my $editsql = 1;
269
                $template->param(
270
                    'save_successful'       => 1,
271
                    'reportname'            => $reportname,
272
                    'id'                    => $id,
273
                    'editsql'               => $editsql,
274
                    'sql'                   => $sql,
275
                    'groups_with_subgroups' => groups_with_subgroups( $group, $subgroup ),
276
                    'notes'                 => $notes,
277
                    'cache_expiry'          => $cache_expiry,
278
                    'public'                => $public,
279
                    'usecache'              => $usecache,
280
                    'tables'                => $tables,
281
                    'report'                => $report
282
                );
283
                logaction( "REPORTS", "MODIFY", $id, "$reportname | $sql" ) if C4::Context->preference("ReportsLog");
284
            }
285
            if ($usecache) {
286
                $template->param(
287
                    cache_expiry       => $cache_expiry,
288
                    cache_expiry_units => $cache_expiry_units,
289
                );
290
            }
233
            if ( $op eq 'cud-update_and_run_sql' ) {
291
            if ( $op eq 'cud-update_and_run_sql' ) {
234
                $editsql = 0;
292
                $op = 'run';
235
            }
293
            }
236
237
            $template->param(
238
                'save_successful'       => 1,
239
                'reportname'            => $reportname,
240
                'id'                    => $id,
241
                'editsql'               => $editsql,
242
                'sql'                   => $sql,
243
                'groups_with_subgroups' => groups_with_subgroups( $group, $subgroup ),
244
                'notes'                 => $notes,
245
                'cache_expiry'          => $cache_expiry,
246
                'public'                => $public,
247
                'usecache'              => $usecache,
248
                'tables'                => $tables
249
            );
250
            logaction( "REPORTS", "MODIFY", $id, "$reportname | $sql" ) if C4::Context->preference("ReportsLog");
251
        }
252
        if ($usecache) {
253
            $template->param(
254
                cache_expiry       => $cache_expiry,
255
                cache_expiry_units => $cache_expiry_units,
256
            );
257
        }
258
        if ( $op eq 'cud-update_and_run_sql' ) {
259
            $op = 'run';
260
        }
294
        }
261
    }
295
    }
262
296
Lines 514-519 if ( !$op ) { Link Here
514
    my $public             = $input->param('public');
548
    my $public             = $input->param('public');
515
    my $save_anyway        = $input->param('save_anyway');
549
    my $save_anyway        = $input->param('save_anyway');
516
    my $tables             = get_tables();
550
    my $tables             = get_tables();
551
    my @branches           = grep { $_ ne q{} } $input->multi_param('branches');
517
552
518
    # if we have the units, then we came from creating a report from SQL and thus need to handle converting units
553
    # if we have the units, then we came from creating a report from SQL and thus need to handle converting units
519
    if ($cache_expiry_units) {
554
    if ($cache_expiry_units) {
Lines 591-596 if ( !$op ) { Link Here
591
                    public         => $public,
626
                    public         => $public,
592
                }
627
                }
593
            );
628
            );
629
            my $report = Koha::Reports->find($id);
630
            $report->replace_library_limits( \@branches );
631
594
            logaction( "REPORTS", "ADD", $id, "$name | $sql" ) if C4::Context->preference("ReportsLog");
632
            logaction( "REPORTS", "ADD", $id, "$name | $sql" ) if C4::Context->preference("ReportsLog");
595
            $template->param(
633
            $template->param(
596
                'save_successful'       => 1,
634
                'save_successful'       => 1,
Lines 603-609 if ( !$op ) { Link Here
603
                'cache_expiry'          => $cache_expiry,
641
                'cache_expiry'          => $cache_expiry,
604
                'public'                => $public,
642
                'public'                => $public,
605
                'usecache'              => $usecache,
643
                'usecache'              => $usecache,
606
                'tables'                => $tables
644
                'tables'                => $tables,
645
                'report'                => $report,
607
            );
646
            );
608
        }
647
        }
609
    }
648
    }
Lines 621-765 if ( !$op ) { Link Here
621
} elsif ( $op eq 'export' ) {
660
} elsif ( $op eq 'export' ) {
622
661
623
    # export results to tab separated text or CSV
662
    # export results to tab separated text or CSV
624
    my $report_id   = $input->param('id');
663
    if ($report) {
625
    my $report      = Koha::Reports->find($report_id);
664
        my $sql         = $report->savedsql;
626
    my $sql         = $report->savedsql;
665
        my @param_names = $input->multi_param('param_name');
627
    my @param_names = $input->multi_param('param_name');
666
        my @sql_params  = $input->multi_param('sql_params');
628
    my @sql_params  = $input->multi_param('sql_params');
667
        my $format      = $input->param('format');
629
    my $format      = $input->param('format');
668
        my $reportname  = $input->param('reportname');
630
    my $reportname  = $input->param('reportname');
669
        my $reportfilename =
631
    my $reportfilename =
670
            $reportname ? "$report_id-$reportname-reportresults.$format" : "$report_id-reportresults.$format";
632
        $reportname ? "$report_id-$reportname-reportresults.$format" : "$report_id-reportresults.$format";
671
        my $scrubber = C4::Scrubber->new();
633
    my $scrubber = C4::Scrubber->new();
672
634
673
        ( $sql, undef ) = $report->prep_report( \@param_names, \@sql_params, { export => 1 } );
635
    ( $sql, undef ) = $report->prep_report( \@param_names, \@sql_params, { export => 1 } );
674
        my ( $sth, $q_errors ) = execute_query( { sql => $sql, report_id => $report_id } );
636
    my ( $sth, $q_errors ) = execute_query( { sql => $sql, report_id => $report_id } );
675
        unless ( $q_errors and @$q_errors ) {
637
    unless ( $q_errors and @$q_errors ) {
676
            my ( $type, $content );
638
        my ( $type, $content );
677
            if ( $format eq 'tab' ) {
639
        if ( $format eq 'tab' ) {
678
                $type = 'application/octet-stream';
640
            $type = 'application/octet-stream';
679
                $content .= join( "\t", header_cell_values($sth) ) . "\n";
641
            $content .= join( "\t", header_cell_values($sth) ) . "\n";
680
                $content = $scrubber->scrub( Encode::decode( 'UTF-8', $content ) );
642
            $content = $scrubber->scrub( Encode::decode( 'UTF-8', $content ) );
681
                while ( my $row = $sth->fetchrow_arrayref() ) {
643
            while ( my $row = $sth->fetchrow_arrayref() ) {
682
                    $content .= $scrubber->scrub( join( "\t", map { $_ // '' } @$row ) ) . "\n";
644
                $content .= $scrubber->scrub( join( "\t", map { $_ // '' } @$row ) ) . "\n";
683
                }
645
            }
684
            } else {
646
        } else {
685
                if ( $format eq 'csv' ) {
647
            if ( $format eq 'csv' ) {
686
                    my $delimiter = C4::Context->csv_delimiter;
648
                my $delimiter = C4::Context->csv_delimiter;
687
                    $type = 'application/csv';
649
                $type = 'application/csv';
650
651
                # Add BOM for UTF-8 encoded CSV
652
                $content .= "\xEF\xBB\xBF";
653
688
654
                my $csv =
689
                    # Add BOM for UTF-8 encoded CSV
655
                    Text::CSV::Encoded->new( { encoding_out => 'UTF-8', sep_char => $delimiter, formula => 'empty' } );
690
                    $content .= "\xEF\xBB\xBF";
656
                $csv or die "Text::CSV::Encoded->new({binary => 1}) FAILED: " . Text::CSV::Encoded->error_diag();
657
                if ( $csv->combine( header_cell_values($sth) ) ) {
658
                    $content .= $scrubber->scrub( Encode::decode( 'UTF-8', $csv->string() ) ) . "\n";
659
691
660
                } else {
692
                    my $csv =
661
                    push @$q_errors, { combine => 'HEADER ROW: ' . $csv->error_diag() };
693
                        Text::CSV::Encoded->new(
662
                }
694
                        { encoding_out => 'UTF-8', sep_char => $delimiter, formula => 'empty' } );
663
                while ( my $row = $sth->fetchrow_arrayref() ) {
695
                    $csv or die "Text::CSV::Encoded->new({binary => 1}) FAILED: " . Text::CSV::Encoded->error_diag();
664
                    if ( $csv->combine(@$row) ) {
696
                    if ( $csv->combine( header_cell_values($sth) ) ) {
665
                        $content .= $scrubber->scrub( $csv->string() ) . "\n";
697
                        $content .= $scrubber->scrub( Encode::decode( 'UTF-8', $csv->string() ) ) . "\n";
666
698
667
                    } else {
699
                    } else {
668
                        push @$q_errors, { combine => $csv->error_diag() };
700
                        push @$q_errors, { combine => 'HEADER ROW: ' . $csv->error_diag() };
669
                    }
701
                    }
670
                }
702
                    while ( my $row = $sth->fetchrow_arrayref() ) {
671
            } elsif ( $format eq 'ods' && C4::Context->preference('ReportsExportFormatODS') ) {
703
                        if ( $csv->combine(@$row) ) {
672
                $type = 'application/vnd.oasis.opendocument.spreadsheet';
704
                            $content .= $scrubber->scrub( $csv->string() ) . "\n";
673
                my $ods_fh       = File::Temp->new( UNLINK => 0 );
705
674
                my $ods_filepath = $ods_fh->filename;
706
                        } else {
675
                my $ods_content;
707
                            push @$q_errors, { combine => $csv->error_diag() };
676
708
                        }
677
                # First line is headers
709
                    }
678
                my @headers = header_cell_values($sth);
710
                } elsif ( $format eq 'ods' && C4::Context->preference('ReportsExportFormatODS') ) {
679
                push @$ods_content, \@headers;
711
                    $type = 'application/vnd.oasis.opendocument.spreadsheet';
680
712
                    my $ods_fh       = File::Temp->new( UNLINK => 0 );
681
                # Other line in Unicode
713
                    my $ods_filepath = $ods_fh->filename;
682
                my $sql_rows = $sth->fetchall_arrayref();
714
                    my $ods_content;
683
                foreach my $sql_row (@$sql_rows) {
715
684
                    my @content_row;
716
                    # First line is headers
685
                    foreach my $sql_cell (@$sql_row) {
717
                    my @headers = header_cell_values($sth);
686
                        push @content_row, $scrubber->scrub( Encode::encode( 'UTF8', $sql_cell ) );
718
                    push @$ods_content, \@headers;
719
720
                    # Other line in Unicode
721
                    my $sql_rows = $sth->fetchall_arrayref();
722
                    foreach my $sql_row (@$sql_rows) {
723
                        my @content_row;
724
                        foreach my $sql_cell (@$sql_row) {
725
                            push @content_row, $scrubber->scrub( Encode::encode( 'UTF8', $sql_cell ) );
687
726
727
                        }
728
                        push @$ods_content, \@content_row;
688
                    }
729
                    }
689
                    push @$ods_content, \@content_row;
690
                }
691
730
692
                # Process
731
                    # Process
693
                generate_ods( $ods_filepath, $ods_content );
732
                    generate_ods( $ods_filepath, $ods_content );
733
734
                    # Output
735
                    binmode(STDOUT);
736
                    open $ods_fh, '<', $ods_filepath;
737
                    print $input->header(
738
                        -type       => $type,
739
                        -attachment => $reportfilename
740
                    );
741
                    print $_ while <$ods_fh>;
742
                    unlink $ods_filepath;
743
                } elsif ( $format eq 'template' ) {
744
                    my $template_id     = $input->param('template');
745
                    my $notice_template = Koha::Notice::Templates->find($template_id);
746
                    my $data            = $sth->fetchall_arrayref( {} );
747
                    $content = process_tt(
748
                        $notice_template->content,
749
                        {
750
                            data         => $data,
751
                            report_id    => $report_id,
752
                            for_download => 1,
753
                        }
754
                    );
755
                    $reportfilename = process_tt(
756
                        $notice_template->title,
757
                        {
758
                            data      => $data,
759
                            report_id => $report_id,
760
                        }
761
                    );
762
                }
763
            }
694
764
695
                # Output
765
            unless ( $format eq 'ods' ) {
696
                binmode(STDOUT);
697
                open $ods_fh, '<', $ods_filepath;
698
                print $input->header(
766
                print $input->header(
699
                    -type       => $type,
767
                    -type       => $type,
700
                    -attachment => $reportfilename
768
                    -attachment => $reportfilename
701
                );
769
                );
702
                print $_ while <$ods_fh>;
770
                print $content;
703
                unlink $ods_filepath;
704
            } elsif ( $format eq 'template' ) {
705
                my $template_id     = $input->param('template');
706
                my $notice_template = Koha::Notice::Templates->find($template_id);
707
                my $data            = $sth->fetchall_arrayref( {} );
708
                $content = process_tt(
709
                    $notice_template->content,
710
                    {
711
                        data         => $data,
712
                        report_id    => $report_id,
713
                        for_download => 1,
714
                    }
715
                );
716
                $reportfilename = process_tt(
717
                    $notice_template->title,
718
                    {
719
                        data      => $data,
720
                        report_id => $report_id,
721
                    }
722
                );
723
            }
771
            }
724
        }
725
772
726
        unless ( $format eq 'ods' ) {
773
            foreach my $err ( @$q_errors, @errors ) {
727
            print $input->header(
774
                print "# ERROR: " . ( map { $_ . ": " . $err->{$_} } keys %$err ) . "\n";
728
                -type       => $type,
775
            }    # here we print all the non-fatal errors at the end.  Not super smooth, but better than nothing.
729
                -attachment => $reportfilename
776
            exit;
730
            );
731
            print $content;
732
        }
777
        }
733
778
        $template->param(
734
        foreach my $err ( @$q_errors, @errors ) {
779
            'sql'     => $sql,
735
            print "# ERROR: " . ( map { $_ . ": " . $err->{$_} } keys %$err ) . "\n";
780
            'execute' => 1,
736
        }    # here we print all the non-fatal errors at the end.  Not super smooth, but better than nothing.
781
            'name'    => 'Error exporting report!',
737
        exit;
782
            'notes'   => '',
783
            'errors'  => $q_errors,
784
        );
738
    }
785
    }
739
    $template->param(
740
        'sql'     => $sql,
741
        'execute' => 1,
742
        'name'    => 'Error exporting report!',
743
        'notes'   => '',
744
        'errors'  => $q_errors,
745
    );
746
786
747
} elsif ( $op eq 'add_form_sql' || $op eq 'duplicate' ) {
787
} elsif ( $op eq 'add_form_sql' || $op eq 'duplicate' ) {
748
788
749
    my ( $group, $subgroup, $sql, $reportname, $notes );
789
    my ( $group, $subgroup, $sql, $reportname, $notes, @branches, $report );
750
    if ( $input->param('sql') ) {
790
    if ( $input->param('sql') ) {
751
        $group      = $input->param('report_group');
791
        $group      = $input->param('report_group');
752
        $subgroup   = $input->param('report_subgroup');
792
        $subgroup   = $input->param('report_subgroup');
753
        $sql        = $input->param('sql')        // '';
793
        $sql        = $input->param('sql')        // '';
754
        $reportname = $input->param('reportname') // '';
794
        $reportname = $input->param('reportname') // '';
755
        $notes      = $input->param('notes')      // '';
795
        $notes      = $input->param('notes')      // '';
796
        @branches   = grep { $_ ne q{} } $input->multi_param('branches');
797
756
    } elsif ( my $report_id = $input->param('id') ) {
798
    } elsif ( my $report_id = $input->param('id') ) {
757
        my $report = Koha::Reports->find($report_id);
799
        $report     = Koha::Reports->find($report_id);
758
        $group      = $report->report_group;
800
        $group      = $report->report_group;
759
        $subgroup   = $report->report_subgroup;
801
        $subgroup   = $report->report_subgroup;
760
        $sql        = $report->savedsql    // '';
802
        $sql        = $report->savedsql    // '';
761
        $reportname = $report->report_name // '';
803
        $reportname = $report->report_name // '';
762
        $notes      = $report->notes       // '';
804
        $notes      = $report->notes       // '';
805
        @branches   = grep { $_ ne q{} } $input->multi_param('branches');
806
763
    }
807
    }
764
808
765
    my $tables = get_tables();
809
    my $tables = get_tables();
Lines 774-779 if ( !$op ) { Link Here
774
        'cache_expiry'          => 300,
818
        'cache_expiry'          => 300,
775
        'usecache'              => $usecache,
819
        'usecache'              => $usecache,
776
        'tables'                => $tables,
820
        'tables'                => $tables,
821
        'report'                => $report,
777
822
778
    );
823
    );
779
}
824
}
Lines 783-789 if ( $op eq 'run' ) { Link Here
783
    # execute a saved report
828
    # execute a saved report
784
    my $limit           = $input->param('limit') || 20;
829
    my $limit           = $input->param('limit') || 20;
785
    my $offset          = 0;
830
    my $offset          = 0;
786
    my $report_id       = $input->param('id');
787
    my @sql_params      = $input->multi_param('sql_params');
831
    my @sql_params      = $input->multi_param('sql_params');
788
    my @param_names     = $input->multi_param('param_name');
832
    my @param_names     = $input->multi_param('param_name');
789
    my $template_id     = $input->param('template');
833
    my $template_id     = $input->param('template');
Lines 800-806 if ( $op eq 'run' ) { Link Here
800
    );
844
    );
801
845
802
    my ( $sql, $original_sql, $type, $name, $notes );
846
    my ( $sql, $original_sql, $type, $name, $notes );
803
    if ( my $report = Koha::Reports->find($report_id) ) {
847
    if ($report) {
804
        $sql   = $original_sql = $report->savedsql;
848
        $sql   = $original_sql = $report->savedsql;
805
        $name  = $report->report_name;
849
        $name  = $report->report_name;
806
        $notes = $report->notes;
850
        $notes = $report->notes;
Lines 1047-1054 if ( $op eq 'run' ) { Link Here
1047
                'param_names' => \@param_names,
1091
                'param_names' => \@param_names,
1048
            );
1092
            );
1049
        }
1093
        }
1050
    } else {
1051
        push @errors, { no_sql_for_id => $report_id };
1052
    }
1094
    }
1053
}
1095
}
1054
1096
Lines 1077-1087 if ( $op eq 'list' || $op eq 'convert' ) { Link Here
1077
1119
1078
    # use a saved report
1120
    # use a saved report
1079
    # get list of reports and display them
1121
    # get list of reports and display them
1080
    my $group    = $input->param('group');
1122
    my $group             = $input->param('group');
1081
    my $subgroup = $input->param('subgroup');
1123
    my $subgroup          = $input->param('subgroup');
1124
    my $show_all_filter   = $filter->{show_all_reports};
1125
    my $logged_in_user    = Koha::Patrons->find($borrowernumber);
1126
    my $can_manage_limits = Koha::Report->can_manage_limits($logged_in_user);
1082
    $filter->{group}    = $group;
1127
    $filter->{group}    = $group;
1083
    $filter->{subgroup} = $subgroup;
1128
    $filter->{subgroup} = $subgroup;
1129
1130
    if ($show_all_filter) {
1131
        $filter->{show_all_reports} = $can_manage_limits ? $show_all_filter : 0;
1132
    } else {
1133
        $filter->{show_all_reports} = 0;
1134
    }
1135
1084
    my $reports = get_saved_reports($filter);
1136
    my $reports = get_saved_reports($filter);
1137
1138
    my $branch_limit_active =
1139
           C4::Context->preference('LimitReportsByBranch')
1140
        && $can_manage_limits
1141
        && !$filter->{show_all_reports};
1142
1085
    my $has_obsolete_reports;
1143
    my $has_obsolete_reports;
1086
    for my $report (@$reports) {
1144
    for my $report (@$reports) {
1087
        $report->{results} = C4::Reports::Guided::get_results( $report->{id} );
1145
        $report->{results} = C4::Reports::Guided::get_results( $report->{id} );
Lines 1091-1103 if ( $op eq 'list' || $op eq 'convert' ) { Link Here
1091
        }
1149
        }
1092
    }
1150
    }
1093
    $template->param(
1151
    $template->param(
1094
        'manamsg'               => $input->param('manamsg') || '',
1152
        'manamsg'                => $input->param('manamsg') || '',
1095
        'saved1'                => 1,
1153
        'saved1'                 => 1,
1096
        'savedreports'          => $reports,
1154
        'savedreports'           => $reports,
1097
        'usecache'              => $usecache,
1155
        'usecache'               => $usecache,
1098
        'groups_with_subgroups' => groups_with_subgroups( $group, $subgroup ),
1156
        'groups_with_subgroups'  => groups_with_subgroups( $group, $subgroup ),
1099
        filters                 => $filter,
1157
        filters                  => $filter,
1100
        has_obsolete_reports    => $has_obsolete_reports,
1158
        has_obsolete_reports     => $has_obsolete_reports,
1159
        branch_limit_active      => $branch_limit_active,
1160
        can_manage_report_limits => $can_manage_limits,
1101
    );
1161
    );
1102
}
1162
}
1103
1163
Lines 1208-1211 sub create_non_existing_group_and_subgroup { Link Here
1208
        }
1268
        }
1209
    }
1269
    }
1210
}
1270
}
1211
(-)a/t/Koha/Auth/Permissions.t (+2 lines)
Lines 63-68 subtest 'normal staff user test' => sub { Link Here
63
        'CAN_user_reports_create_reports'                    => 1,
63
        'CAN_user_reports_create_reports'                    => 1,
64
        'CAN_user_reports_delete_reports'                    => 1,
64
        'CAN_user_reports_delete_reports'                    => 1,
65
        'CAN_user_reports_execute_reports'                   => 1,
65
        'CAN_user_reports_execute_reports'                   => 1,
66
        'CAN_user_reports_manage_report_limits'              => 1,
66
    };
67
    };
67
    is_deeply( $authz, $expected, 'Expected permissions generated for normal staff user' );
68
    is_deeply( $authz, $expected, 'Expected permissions generated for normal staff user' );
68
};
69
};
Lines 228-233 subtest 'superlibrarian tests' => sub { Link Here
228
        'CAN_user_reports_create_reports'                           => 1,
229
        'CAN_user_reports_create_reports'                           => 1,
229
        'CAN_user_reports_delete_reports'                           => 1,
230
        'CAN_user_reports_delete_reports'                           => 1,
230
        'CAN_user_reports_execute_reports'                          => 1,
231
        'CAN_user_reports_execute_reports'                          => 1,
232
        'CAN_user_reports_manage_report_limits'                     => 1,
231
        'CAN_user_reports'                                          => 1,
233
        'CAN_user_reports'                                          => 1,
232
        'CAN_user_reserveforothers_modify_holds_priority'           => 1,
234
        'CAN_user_reserveforothers_modify_holds_priority'           => 1,
233
        'CAN_user_reserveforothers_place_holds'                     => 1,
235
        'CAN_user_reserveforothers_place_holds'                     => 1,
(-)a/t/db_dependent/Koha/Reports.t (-1 / +103 lines)
Lines 18-24 Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::NoWarnings;
20
use Test::NoWarnings;
21
use Test::More tests => 9;
21
use Test::More tests => 11;
22
22
23
use Koha::Report;
23
use Koha::Report;
24
use Koha::Reports;
24
use Koha::Reports;
Lines 185-188 subtest '_might_add_limit' => sub { Link Here
185
    );
185
    );
186
};
186
};
187
187
188
subtest 'reports_branches are added and removed from report_branches table' => sub {
189
    plan tests => 4;
190
191
    my $updated_nb_of_reports = Koha::Reports->search->count;
192
    my $report                = Koha::Report->new(
193
        {
194
            report_name => 'report_name_for_test_1',
195
            savedsql    => 'SELECT * FROM items WHERE itemnumber IN <<Test|list>>',
196
        }
197
    )->store;
198
199
    my $id       = $report->id;
200
    my $library1 = $builder->build_object( { class => 'Koha::Libraries' } );
201
    my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
202
    my $library3 = $builder->build_object( { class => 'Koha::Libraries' } );
203
    my @branches = ( $library1->branchcode, $library2->branchcode, $library3->branchcode );
204
205
    $report->replace_library_limits( \@branches );
206
207
    my @branches_loop = $report->get_library_limits->as_list;
208
    is( scalar @branches_loop, 3, '3 branches added to report_branches table' );
209
210
    $report->replace_library_limits( [ $library1->branchcode, $library2->branchcode ] );
211
212
    @branches_loop = $report->get_library_limits->as_list;
213
    is( scalar @branches_loop, 2, '1 branch removed from report_branches table' );
214
215
    $report->delete;
216
    is( Koha::Reports->search->count, $updated_nb_of_reports, 'Report deleted, count is back to original' );
217
    is(
218
        $schema->resultset('ReportsBranch')->search( { report_id => $id } )->count,
219
        0,
220
        'No branches left in reports_branches table after report deletion'
221
    );
222
};
223
224
subtest 'can_manage_limits and can_access' => sub {
225
    plan tests => 21;
226
227
    my $libraryA = $builder->build_object( { class => 'Koha::Libraries' } );
228
    my $libraryB = $builder->build_object( { class => 'Koha::Libraries' } );
229
    my $branchA  = $libraryA->branchcode;
230
    my $branchB  = $libraryB->branchcode;
231
232
    my $super_patron =
233
        $builder->build_object( { class => 'Koha::Patrons', value => { flags => 1, branchcode => $branchA } } );
234
    my $mgr_patron   = $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $branchA } } );
235
    my $basic_patron = $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $branchA } } );
236
237
    # Grant reports => manage_report_limits to manager patron (create permission if missing)
238
    my $perm = $schema->resultset('Permission')->find( { module_bit => 16, code => 'manage_report_limits' } )
239
        // $schema->resultset('Permission')
240
        ->create( { module_bit => 16, code => 'manage_report_limits', description => 'Manage report limits' } );
241
    $schema->resultset('UserPermission')
242
        ->create( { borrowernumber => $mgr_patron->borrowernumber, module_bit => 16, code => 'manage_report_limits' } );
243
244
    # Helper to create reports
245
    my $r_no = Koha::Report->new( { report_name => 'No limits', savedsql => 'SELECT 1' } )->store;
246
    my $r_A  = Koha::Report->new( { report_name => 'Limit A',   savedsql => 'SELECT 1' } )->store;
247
    my $r_B  = Koha::Report->new( { report_name => 'Limit B',   savedsql => 'SELECT 1' } )->store;
248
    my $r_AB = Koha::Report->new( { report_name => 'Limit AB',  savedsql => 'SELECT 1' } )->store;
249
250
    $r_A->replace_library_limits( [$branchA] );
251
    $r_B->replace_library_limits( [$branchB] );
252
    $r_AB->replace_library_limits( [ $branchA, $branchB ] );
253
254
    # Preference ON, branch A
255
    t::lib::Mocks::mock_preference( 'LimitReportsByBranch', 1 );
256
    t::lib::Mocks::mock_userenv( { branchcode => $branchA } );
257
258
    ok( Koha::Report->can_manage_limits($super_patron),  'pref ON: super manages limits' );
259
    ok( Koha::Report->can_manage_limits($mgr_patron),    'pref ON: manager manages limits' );
260
    ok( !Koha::Report->can_manage_limits($basic_patron), 'pref ON: basic cannot manage limits' );
261
262
    # Basic patron (branch A)
263
    ok( $r_no->can_access($basic_patron), 'pref ON: no limits accessible' );
264
    ok( $r_A->can_access($basic_patron),  'pref ON: limited includes branch accessible' );
265
    ok( !$r_B->can_access($basic_patron), 'pref ON: limited excludes branch denied' );
266
    ok( $r_AB->can_access($basic_patron), 'pref ON: multi includes branch accessible' );
267
268
    # Manager bypass (branch A)
269
    ok( $r_A->can_access($mgr_patron),  'pref ON: manager sees limited A' );
270
    ok( $r_B->can_access($mgr_patron),  'pref ON: manager sees limited B' );
271
    ok( $r_AB->can_access($mgr_patron), 'pref ON: manager sees multi AB' );
272
    ok( $r_no->can_access($mgr_patron), 'pref ON: manager sees no limits' );
273
274
    # Superlibrarian bypass (branch A)
275
    ok( $r_A->can_access($super_patron),  'pref ON: super sees limited A' );
276
    ok( $r_B->can_access($super_patron),  'pref ON: super sees limited B' );
277
    ok( $r_AB->can_access($super_patron), 'pref ON: super sees multi AB' );
278
279
    # Preference OFF (everything accessible, manage disabled)
280
    t::lib::Mocks::mock_preference( 'LimitReportsByBranch', 0 );
281
    ok( !Koha::Report->can_manage_limits($super_patron), 'pref OFF: super cannot manage limits' );
282
    ok( !Koha::Report->can_manage_limits($mgr_patron),   'pref OFF: manager cannot manage limits' );
283
    ok( !Koha::Report->can_manage_limits($basic_patron), 'pref OFF: basic cannot manage limits' );
284
    ok( $r_B->can_access($basic_patron),                 'pref OFF: limited excludes branch still accessible' );
285
    ok( $r_A->can_access($basic_patron),                 'pref OFF: limited includes branch accessible' );
286
    ok( $r_AB->can_access($basic_patron),                'pref OFF: multi-limit accessible' );
287
    ok( $r_no->can_access($basic_patron),                'pref OFF: no limits accessible' );
288
};
289
188
$schema->storage->txn_rollback;
290
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Reports/Guided.t (-1 / +86 lines)
Lines 21-27 Link Here
21
use Modern::Perl;
21
use Modern::Perl;
22
22
23
use Test::NoWarnings;
23
use Test::NoWarnings;
24
use Test::More tests => 14;
24
use Test::More tests => 15;
25
use Test::Warn;
25
use Test::Warn;
26
26
27
use t::lib::TestBuilder;
27
use t::lib::TestBuilder;
Lines 324-329 subtest 'get_saved_reports' => sub { Link Here
324
    );
324
    );
325
};
325
};
326
326
327
subtest 'get_saved_reports branch limits' => sub {
328
    my $schema = Koha::Database->new->schema;
329
    my $dbh    = C4::Context->dbh;
330
331
    # Skip gracefully if the feature table is not present (e.g. older schema)
332
    my $sth = $dbh->prepare(q{SHOW TABLES LIKE 'reports_library_limits'});
333
    $sth->execute;
334
    my ($exists) = $sth->fetchrow_array;
335
    unless ($exists) {
336
        plan skip_all => 'reports_library_limits table not present; skipping branch limits tests';
337
        return;
338
    }
339
340
    plan tests => 13;
341
342
    # Clean related tables
343
    $dbh->do(q|DELETE FROM saved_sql|);
344
    $dbh->do(q|DELETE FROM saved_reports|);
345
    $dbh->do(q|DELETE FROM reports_library_limits|);
346
347
    # Build two libraries (branches)
348
    my $lib_a = $builder->build( { source => 'Branch', value => 'Library A' } );
349
    my $lib_b = $builder->build( { source => 'Branch', value => 'Library B' } );
350
351
    # Mock userenv to lib_a
352
    t::lib::Mocks::mock_userenv( { branchcode => $lib_a->{branchcode} } );
353
354
    # Build three reports
355
    my @ids;
356
    foreach my $n ( 1 .. 3 ) {
357
        push @ids, save_report(
358
            {
359
                borrowernumber => $builder->build( { source => 'Borrower' } )->{borrowernumber},
360
                sql            => "SELECT $n",
361
                name           => "Report $n",
362
                area           => 'CIRC',
363
                group          => 'G',
364
                subgroup       => 'SG',
365
                type           => 'T',
366
                notes          => undef,
367
                cache_expiry   => undef,
368
                public         => 0,
369
            }
370
        );
371
    }
372
373
    my ( $r1, $r2, $r3 ) = map { Koha::Reports->find($_) } @ids;
374
375
    # Apply library limits to first two reports (r1 => lib_a only, r2 => lib_b only)
376
    $r1->replace_library_limits( [ $lib_a->{branchcode} ] );
377
    $r2->replace_library_limits( [ $lib_b->{branchcode} ] );
378
379
    # r3 has no limits
380
381
    # Preference OFF: should ignore limits, return all three, no library_limits metadata
382
    t::lib::Mocks::mock_preference( 'LimitReportsByBranch', 0 );
383
    my $all_pref_off = get_saved_reports();
384
    is( scalar(@$all_pref_off), 3, 'Pref OFF returns all reports' );
385
    ok( !defined $all_pref_off->[0]{library_limits}, 'Pref OFF does not attach metadata' );
386
387
    # Preference ON, filtering applied (userenv branch is lib_a)
388
    t::lib::Mocks::mock_preference( 'LimitReportsByBranch', 1 );
389
    my $filtered = get_saved_reports();
390
    is( scalar(@$filtered), 2, 'Pref ON filters reports by user branch and unrestricted reports' );
391
    my @filtered_ids = sort map { $_->{id} } @$filtered;
392
    my @expected_ids = sort ( $r1->id, $r3->id );          # r1 limited to lib_a + r3 unrestricted
393
    is_deeply( \@filtered_ids, \@expected_ids, 'Filtered list contains branch-limited and unrestricted reports' );
394
    foreach my $r (@$filtered) {
395
        ok( defined $r->{library_limits}, 'Metadata attached on pref ON filtered path' );
396
    }
397
    my ($meta_r1) = grep { $_->{id} == $r1->id } @$filtered;
398
    is_deeply( $meta_r1->{library_limits}, [ $lib_a->{branchcode} ], 'r1 metadata lists its single limit' );
399
    my ($meta_r3) = grep { $_->{id} == $r3->id } @$filtered;
400
    is_deeply( $meta_r3->{library_limits}, [], 'Unrestricted r3 has empty limits array' );
401
402
    # Preference ON + show_all_reports flag: should return all, with metadata for all
403
    my $show_all = get_saved_reports( { show_all_reports => 1 } );
404
    is( scalar(@$show_all), 3, 'show_all_reports returns all reports when pref ON' );
405
    foreach my $r (@$show_all) {
406
        ok( defined $r->{library_limits}, 'Metadata attached for each report in show_all path' );
407
    }
408
    my ($show_r2) = grep { $_->{id} == $r2->id } @$show_all;
409
    is_deeply( $show_r2->{library_limits}, [ $lib_b->{branchcode} ], 'r2 metadata lists its limit under show_all' );
410
};
411
327
subtest 'Ensure last_run is populated' => sub {
412
subtest 'Ensure last_run is populated' => sub {
328
    plan tests => 3;
413
    plan tests => 3;
329
414
(-)a/tools/scheduler.pl (-6 / +36 lines)
Lines 27-32 use C4::Output qw( output_html_with_http_headers ); Link Here
27
use Koha::DateUtils     qw( dt_from_string );
27
use Koha::DateUtils     qw( dt_from_string );
28
use Koha::Reports;
28
use Koha::Reports;
29
use Koha::Email;
29
use Koha::Email;
30
use Koha::Patrons;
31
use Koha::Report;
30
32
31
my $input = CGI->new;
33
my $input = CGI->new;
32
my $base;
34
my $base;
Lines 48-55 my ( $template, $borrowernumber, $cookie ) = get_template_and_user( Link Here
48
    }
50
    }
49
);
51
);
50
52
51
my $op = $input->param('op') // q{};
53
my $op                 = $input->param('op') // q{};
52
my $id = $input->param('id');
54
my $id                 = $input->param('id');
55
my $selected_report_id = $input->param('report');
56
my $selected_report    = $selected_report_id ? Koha::Reports->find($selected_report_id) : undef;
57
if ( $op eq 'cud-add' && $selected_report_id ) {
58
    my $logged_in_user = Koha::Patrons->find($borrowernumber);
59
    if ( !$selected_report ) {
60
        $template->param( no_sql_for_id => $selected_report_id, access_denied => 1 );
61
        $op = '';
62
    } elsif ( !$selected_report->can_access($logged_in_user) ) {
63
        $template->param( access_denied => 1, id => $selected_report_id );
64
        $op = '';
65
    }
66
}
53
67
54
if ( $op eq 'cud-add' ) {
68
if ( $op eq 'cud-add' ) {
55
69
Lines 111-124 foreach my $job ( values %$jobs ) { Link Here
111
125
112
@jobloop = sort { $a->{TIME} cmp $b->{TIME} } @jobloop;
126
@jobloop = sort { $a->{TIME} cmp $b->{TIME} } @jobloop;
113
127
114
my $reports = get_saved_reports();
128
my $logged_in_user    = Koha::Patrons->find($borrowernumber);
129
my $can_manage_limits = Koha::Report->can_manage_limits($logged_in_user);
130
131
my $reports =
132
    $can_manage_limits
133
    ? get_saved_reports( { show_all_reports => 1 } )
134
    : get_saved_reports();
135
136
my @final_reports;
137
if ($can_manage_limits) {
138
    @final_reports = @$reports;
139
} else {
140
    @final_reports = grep {
141
        my $r_obj = Koha::Reports->find( $_->{id} );
142
        $r_obj && $r_obj->can_access($logged_in_user);
143
    } @$reports;
144
}
145
115
if ( defined $id ) {
146
if ( defined $id ) {
116
    foreach my $report (@$reports) {
147
    foreach my $report (@final_reports) {
117
        $report->{'selected'} = 1 if $report->{'id'} eq $id;
148
        $report->{'selected'} = 1 if $report->{'id'} eq $id;
118
    }
149
    }
119
}
150
}
120
151
121
$template->param( 'savedreports' => $reports );
152
$template->param( 'savedreports' => \@final_reports );
122
$template->param( JOBS           => \@jobloop );
153
$template->param( JOBS           => \@jobloop );
123
my $time = localtime(time);
154
my $time = localtime(time);
124
$template->param( 'time' => $time );
155
$template->param( 'time' => $time );
125
- 

Return to bug 16631