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

(-)a/Koha/ERM/EUsage/COUNTER/5.pm (+335 lines)
Line 0 Link Here
1
package Koha::ERM::EUsage::COUNTER::5;
2
3
# Copyright 2025 Open Fifth
4
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use base qw(Koha::ERM::EUsage::SushiCounter);
23
24
=head1 NAME
25
26
Koha::ERM::EUsage::COUNTER::5 - Koha COUNTER 5 Object class
27
28
=head1 API
29
30
=head2 Class Methods
31
32
=head3 new
33
34
    my $sushi_counter =
35
        Koha::ERM::EUsage::SushiCounter->new( { response => decode_json( $response->decoded_content ) } );
36
37
=cut
38
39
sub new {
40
    my ($class) = @_;
41
    my $self = {};
42
43
    bless( $self, $class );
44
}
45
46
=head3 _COUNTER_report_header
47
48
Return a COUNTER report header
49
https://cop5.projectcounter.org/en/5.0.2/04-reports/03-title-reports.html
50
51
=cut
52
53
sub _COUNTER_report_header {
54
    my ($self) = @_;
55
56
    my $header = $self->{sushi}->{header};
57
58
    my @metric_types_string = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "Metric_Type" );
59
60
    my $begin_date = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "Begin_Date" );
61
    my $end_date   = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "End_Date" );
62
63
    return (
64
        [ Report_Name      => $header->{Report_Name}                                                            || "" ],
65
        [ Report_ID        => $header->{Report_ID}                                                              || "" ],
66
        [ Release          => $header->{Release}                                                                || "" ],
67
        [ Institution_Name => $header->{Institution_Name}                                                       || "" ],
68
        [ Institution_ID => join( "; ", map( $_->{Type} . ":" . $_->{Value}, @{ $header->{Institution_ID} } ) ) || "" ],
69
        [ Metric_Types   => join( "; ", split( /\|/, $metric_types_string[0] ) )                                || "" ],
70
        [ Report_Filters => join( "; ", map( $_->{Name} . ":" . $_->{Value}, @{ $header->{Report_Filters} } ) ) || "" ],
71
72
        #TODO: Report_Attributes may need parsing, test this with a SUSHI response that provides it
73
        [ Report_Attributes => $header->{Report_Attributes} || "" ],
74
        [
75
            Exceptions => join(
76
                "; ", map( $_->{Code} . ": " . $_->{Message} . " (" . $_->{Data} . ")", @{ $header->{Exceptions} } )
77
                )
78
                || ""
79
        ],
80
        [ Reporting_Period => "Begin_Date=" . $begin_date . "; End_Date=" . $end_date ],
81
        [ Created          => $header->{Created}    || "" ],
82
        [ Created_By       => $header->{Created_By} || "" ],
83
        [""]    #empty 13th line (COUNTER 5)
84
    );
85
}
86
87
=head3 _get_SUSHI_Name_Value
88
89
Returns "Value" of a given "Name"
90
91
=cut
92
93
sub _get_SUSHI_Name_Value {
94
    my ( $self, $item, $name ) = @_;
95
96
    my @value = map( $_->{Name} eq $name ? $_->{Value} : (), @{$item} );
97
    return $value[0];
98
}
99
100
=head3 _get_SUSHI_Type_Value
101
102
Returns "Value" of a given "Type"
103
104
=cut
105
106
sub _get_SUSHI_Type_Value {
107
    my ( $self, $item, $type ) = @_;
108
109
    my @value = map( $_->{Type} eq $type ? $_->{Value} : (), @{$item} );
110
    return $value[0];
111
}
112
113
=head3 _get_COUNTER_row_usages
114
115
Returns the total and monthly usages for a row
116
117
=cut
118
119
sub _get_COUNTER_row_usages {
120
    my ( $self, $row, $metric_type ) = @_;
121
122
    my @usage_months = $self->_get_usage_months( $self->{sushi}->{header} );
123
124
    my @usage_months_fields = ();
125
    my $count_total         = 0;
126
127
    foreach my $usage_month (@usage_months) {
128
        my $month_is_empty = 1;
129
130
        foreach my $performance ( @{ $row->{Performance} } ) {
131
            my $period             = $performance->{Period};
132
            my $period_usage_month = substr( $period->{Begin_Date}, 0, 7 );
133
134
            my $instances = $performance->{Instance};
135
            my @metric_type_count =
136
                map( $_->{Metric_Type} eq $metric_type ? $_->{Count} : (),
137
                @{$instances} );
138
139
            if ( $period_usage_month eq $usage_month && $metric_type_count[0] ) {
140
                push( @usage_months_fields, $metric_type_count[0] );
141
                $count_total += $metric_type_count[0];
142
                $month_is_empty = 0;
143
            }
144
        }
145
146
        if ($month_is_empty) {
147
            push( @usage_months_fields, 0 );
148
        }
149
    }
150
    return ( $count_total, @usage_months_fields );
151
}
152
153
=head3 get_SUSHI_metric_types
154
155
    Returns all metric types this SUSHI result has statistics for, as an array of strings.
156
157
=cut
158
159
sub get_SUSHI_metric_types {
160
    my ( $self, $report_row ) = @_;
161
162
    my @metric_types = ();
163
164
    # Grab all metric_types this SUSHI result has statistics for
165
    foreach my $performance ( @{ $report_row->{Performance} } ) {
166
        my @SUSHI_metric_types =
167
            map( $_->{Metric_Type}, @{ $performance->{Instance} } );
168
169
        foreach my $sushi_metric_type (@SUSHI_metric_types) {
170
            push( @metric_types, $sushi_metric_type ) unless grep { $_ eq $sushi_metric_type } @metric_types;
171
        }
172
    }
173
174
    return @metric_types;
175
}
176
177
=head3 _COUNTER_report_body
178
179
Return the COUNTER report body as an array
180
181
=cut
182
183
sub _COUNTER_report_body {
184
    my ($self) = @_;
185
186
    my $header = $self->{sushi}->{header};
187
    my $body   = $self->{sushi}->{body};
188
189
    my @report_body = ();
190
191
    foreach my $report_row ( @{$body} ) {
192
        my @metric_types = $self->get_SUSHI_metric_types($report_row);
193
194
        # Add one report row for each metric_type we're working with
195
        foreach my $metric_type (@metric_types) {
196
            push( @report_body, $self->_COUNTER_report_row( $report_row, $metric_type ) );
197
        }
198
    }
199
200
    return @report_body;
201
}
202
203
=head3 _COUNTER_title_report_row
204
205
Return a COUNTER title for the COUNTER titles report body
206
https://cop5.projectcounter.org/en/5.0.2/04-reports/03-title-reports.html#column-headings-elements
207
208
=cut
209
210
sub _COUNTER_title_report_row {
211
    my ( $self, $title_row, $metric_type, $total_usage, $monthly_usages ) = @_;
212
213
    my $header          = $self->{sushi}->{header};
214
    my $specific_fields = $self->get_report_type_specific_fields( $header->{Report_ID} );
215
216
    return (
217
        [
218
            # Title
219
            $title_row->{Title} || "",
220
221
            # Publisher
222
            $title_row->{Publisher} || "",
223
224
            # Publisher_ID
225
            $self->_get_SUSHI_Type_Value( $title_row->{Publisher_ID}, "ISNI" ) || "",
226
227
            # Platform
228
            $title_row->{Platform} || "",
229
230
            # DOI
231
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "DOI" ) || "",
232
233
            # Proprietary_ID
234
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Proprietary" ) || "",
235
236
            # ISBN
237
            grep ( /ISBN/, @{$specific_fields} )
238
            ? ( $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "ISBN" ) || "" )
239
            : (),
240
241
            # Print_ISSN
242
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Print_ISSN" ) || "",
243
244
            # Online_ISSN
245
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Online_ISSN" ) || "",
246
247
            # URI - FIXME: What goes in URI?
248
            "",
249
250
            # YOP
251
            grep ( /YOP/, @{$specific_fields} ) ? ( $title_row->{YOP} || "" ) : (),
252
253
            # Access_Type
254
            grep ( /Access_Type/, @{$specific_fields} ) ? ( $title_row->{Access_Type} || "" ) : (),
255
256
            # Metric_Type
257
            $metric_type,
258
259
            # Report_Period_Total
260
            $total_usage,
261
262
            # Monthly usage entries
263
            @{$monthly_usages}
264
        ]
265
    );
266
}
267
268
=head3 _COUNTER_titles_report_column_headings
269
270
Return titles report column headings
271
272
=cut
273
274
sub _COUNTER_titles_report_column_headings {
275
    my ($self) = @_;
276
277
    my $header          = $self->{sushi}->{header};
278
    my @month_headings  = $self->_get_usage_months( $header, 1 );
279
    my $specific_fields = $self->get_report_type_specific_fields( $header->{Report_ID} );
280
281
    return (
282
        [
283
            "Title",
284
            "Publisher",
285
            "Publisher_ID",
286
            "Platform",
287
            "DOI",
288
            "Proprietary_ID",
289
            grep ( /ISBN/, @{$specific_fields} ) ? ("ISBN") : (),
290
            "Print_ISSN",
291
            "Online_ISSN",
292
            "URI",
293
294
            #"Data_Type", #TODO: Only if requested (?)
295
            #"Section_Type", #TODO: Only if requested (?)
296
            grep ( /YOP/,         @{$specific_fields} ) ? ("YOP")         : (),
297
            grep ( /Access_Type/, @{$specific_fields} ) ? ("Access_Type") : (),
298
299
            #"Access_Method", #TODO: Only if requested (?)
300
            "Metric_Type",
301
            "Reporting_Period_Total",
302
303
            # @month_headings in "Mmm-yyyy" format. TODO: Show unless Exclude_Monthly_Details=true
304
            @month_headings
305
        ]
306
    );
307
}
308
309
=head3 get_report_type_specific_fields
310
311
Returns the specific fields for a given report_type
312
313
=cut
314
315
sub get_report_type_specific_fields {
316
    my ( $self, $report_type ) = @_;
317
318
    my %report_type_map = (
319
        "TR_B1" => [ 'YOP', 'ISBN' ],
320
        "TR_B2" => [ 'YOP', 'ISBN' ],
321
        "TR_B3" => [ 'YOP', 'Access_Type', 'ISBN' ],
322
        "TR_J3" => ['Access_Type'],
323
        "TR_J4" => ['YOP'],
324
        "IR_A1" => [
325
            'Authors',            'Publication_Date', 'Article_Version',  'Print_ISSN', 'Online_ISSN', 'Parent_Title',
326
            'Parent_Authors',     'Parent_Article_Version', 'Parent_DOI', 'Parent_Proprietary_ID', 'Parent_Print_ISSN',
327
            'Parent_Online_ISSN', 'Parent_URI',             'Access_Type'
328
        ],
329
    );
330
331
    return $report_type_map{$report_type};
332
333
}
334
335
1;
(-)a/Koha/ERM/EUsage/COUNTER/5_1.pm (+468 lines)
Line 0 Link Here
1
package Koha::ERM::EUsage::COUNTER::5_1;
2
3
# Copyright 2025 Open Fifth
4
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use base qw(Koha::ERM::EUsage::SushiCounter);
23
24
=head1 NAME
25
26
Koha::ERM::EUsage::COUNTER::5 - Koha COUNTER 5.1 Object class
27
28
=head1 API
29
30
=head2 Class Methods
31
32
=head3 new
33
34
    my $sushi_counter =
35
        Koha::ERM::EUsage::SushiCounter->new( { response => decode_json( $response->decoded_content ) } );
36
37
=cut
38
39
sub new {
40
    my ($class) = @_;
41
    my $self = {};
42
43
    bless( $self, $class );
44
}
45
46
=head3 _COUNTER_report_header
47
48
Return a COUNTER report header
49
https://cop5.projectcounter.org/en/5.1/04-reports/03-title-reports.html
50
51
=cut
52
53
sub _COUNTER_report_header {
54
    my ($self) = @_;
55
56
    my $header = $self->{sushi}->{header};
57
58
    my $metric_types       = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "Metric_Type" );
59
    my @metric_types_array = split( /\|/, $metric_types );
60
    $metric_types = join( "; ", @metric_types_array ) if @metric_types_array;
61
62
    my $begin_date = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "Begin_Date" );
63
    my $end_date   = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "End_Date" );
64
65
    return (
66
        [ Report_Name      => $header->{Report_Name}                                              || "" ],
67
        [ Report_ID        => $header->{Report_ID}                                                || "" ],
68
        [ Release          => $header->{Release}                                                  || "" ],
69
        [ Institution_Name => $header->{Institution_Name}                                         || "" ],
70
        [ Institution_ID   => $self->get_mapped_SUSHI_values( 'Type', $header->{Institution_ID} ) || "" ],
71
        [ Metric_Types     => $metric_types                                                       || "" ],
72
        [ Report_Filters   => $self->get_mapped_SUSHI_values( 'Name', $header->{Report_Filters} ) || "" ],
73
74
        #TODO: Report_Attributes may need parsing, test this with a SUSHI response that provides it
75
        [ Report_Attributes => $header->{Report_Attributes} || "" ],
76
        [
77
            Exceptions => join(
78
                "; ", map( $_->{Code} . ": " . $_->{Message} . " (" . $_->{Data} . ")", @{ $header->{Exceptions} } )
79
                )
80
                || ""
81
        ],
82
        [ Reporting_Period => "Begin_Date=" . $begin_date . "; End_Date=" . $end_date ],
83
        [ Created          => $header->{Created}         || "" ],
84
        [ Created_By       => $header->{Created_By}      || "" ],
85
        [ Registry_Record  => $header->{Registry_Record} || "" ],
86
        [""]    #empty 14th line (COUNTER 5.1)
87
    );
88
}
89
90
=head3 get_counter51_value
91
92
    Given a SUSHI response, get the value for the given key in the correct format for the COUNTER report
93
    https://counter5.cambridge.org/r51/sushi-docs/
94
95
=cut
96
97
sub get_counter51_value {
98
    my ( $self, $item, $key ) = @_;
99
    my $counter_51_value = $item->{$key};
100
    if ( ref($counter_51_value) eq 'ARRAY' ) {
101
        return join( "; ", @$counter_51_value );
102
    } else {
103
        return $counter_51_value;
104
    }
105
}
106
107
=head3 get_mapped_SUSHI_values
108
109
    Given a SUSHI response, get the value for the given key in the correct format for the COUNTER report
110
    https://counter5.cambridge.org/r51/sushi-docs/
111
112
    It will return a string of the form "Name:Value;Name:Value;..."
113
    If the value is an array with a single element, just the value will be returned.
114
    If the value is an array with multiple elements, they will be joined with "|"
115
116
=cut
117
118
sub get_mapped_SUSHI_values {
119
    my ( $self, $key, $sushi_type_value ) = @_;
120
121
    return join(
122
        "; ",
123
        map {
124
            $_ . ":"
125
                . (
126
                ref $sushi_type_value->{$_} eq 'ARRAY'
127
                    && scalar( @{ $sushi_type_value->{$_} } ) == 1 ? $sushi_type_value->{$_}[0]
128
                : ( ref $sushi_type_value->{$_} eq 'ARRAY' && scalar( @{ $sushi_type_value->{$_} } ) > 1 )
129
                ? join( "|", @{ $sushi_type_value->{$_} } )
130
                : $sushi_type_value->{$_}
131
                )
132
        } keys %{$sushi_type_value}
133
    );
134
}
135
136
=head3 _get_SUSHI_Name_Value
137
138
Returns "Value" of a given "Name"
139
140
=cut
141
142
sub _get_SUSHI_Name_Value {
143
    my ( $self, $item, $name ) = @_;
144
145
    return $self->get_counter51_value( $item, $name );
146
}
147
148
=head3 _get_SUSHI_Type_Value
149
150
Returns "Value" of a given "Type"
151
152
=cut
153
154
sub _get_SUSHI_Type_Value {
155
    my ( $self, $item, $type ) = @_;
156
157
    return $self->get_counter51_value( $item, $type );
158
}
159
160
=head3 _get_COUNTER_row_usages
161
162
Returns the total and monthly usages for a row
163
164
=cut
165
166
sub _get_COUNTER_row_usages {
167
    my ( $self, $row, $metric_type, $access_type ) = @_;
168
169
    my @usage_months = $self->_get_usage_months( $self->{sushi}->{header} );
170
171
    my @usage_months_fields = ();
172
    my $count_total         = 0;
173
174
    foreach my $usage_month (@usage_months) {
175
        my $month_is_empty = 1;
176
177
        my $usage_to_add;
178
        if ($access_type) {
179
            my @access_type_performances =
180
                grep { $_->{Access_Type} eq $access_type } @{ $row->{Attribute_Performance} };
181
            $usage_to_add = $access_type_performances[0]->{Performance}->{$metric_type}->{$usage_month};
182
        } else {
183
            $usage_to_add = $row->{Attribute_Performance}->[0]->{Performance}->{$metric_type}->{$usage_month};
184
        }
185
        if ( defined $usage_to_add ) {
186
            $count_total += $usage_to_add;
187
            $month_is_empty = 0;
188
            push( @usage_months_fields, $usage_to_add );
189
        }
190
191
        if ($month_is_empty) {
192
            push( @usage_months_fields, 0 );
193
        }
194
    }
195
196
    return ( $count_total, @usage_months_fields );
197
}
198
199
=head3 get_SUSHI_metric_types
200
201
    Given a SUSHI report row, return a sorted list of all the metric types
202
203
=cut
204
205
sub get_SUSHI_metric_types {
206
    my ( $self, $report_row ) = @_;
207
208
    my @metric_types = ();
209
    @metric_types = keys %{ $report_row->{Attribute_Performance}->[0]->{Performance} };
210
    @metric_types = sort @metric_types;
211
    return @metric_types;
212
}
213
214
=head3 _COUNTER_report_body
215
216
Return the COUNTER report body as an array
217
218
=cut
219
220
sub _COUNTER_report_body {
221
    my ($self) = @_;
222
223
    my $header = $self->{sushi}->{header};
224
    my $body   = $self->{sushi}->{body};
225
226
    my @report_body = ();
227
228
    foreach my $report_row ( @{$body} ) {
229
        my @metric_types = $self->get_SUSHI_metric_types($report_row);
230
231
        my $specific_fields = $self->get_report_type_specific_fields( $header->{Report_ID} );
232
        my $use_access_type = grep ( /Access_Type/, @{$specific_fields} ) ? 1 : 0;
233
        my $use_yop         = grep ( /YOP/,         @{$specific_fields} ) ? 1 : 0;
234
        my $use_data_type   = grep ( /Data_Type/,   @{$specific_fields} ) ? 1 : 0;
235
236
        if ($use_data_type) {
237
            my %data_types = map { $_->{Data_Type} => 1 } @{ $report_row->{Attribute_Performance} };
238
            my @data_types = sort keys %data_types;
239
240
            foreach my $data_type (@data_types) {
241
242
                if ($use_yop) {
243
                    my %yops = map  { $_->{YOP} => 1 } @{ $report_row->{Attribute_Performance} };
244
                    my @yops = sort { $b <=> $a } keys %yops;
245
                    foreach my $yop (@yops) {
246
247
                        if ($use_access_type) {
248
                            my @access_types = map { $_->{"Access_Type"} } @{ $report_row->{Attribute_Performance} };
249
                            foreach my $access_type (@access_types) {
250
251
                                # Add one report row for each metric_type we're working with
252
                                foreach my $metric_type (@metric_types) {
253
                                    push(
254
                                        @report_body,
255
                                        $self->_COUNTER_report_row(
256
                                            $report_row, $metric_type, $access_type, $yop,
257
                                            $data_type
258
                                        )
259
                                    );
260
                                }
261
                            }
262
                        } else {
263
264
                            # Add one report row for each metric_type we're working with
265
                            foreach my $metric_type (@metric_types) {
266
                                push(
267
                                    @report_body,
268
                                    $self->_COUNTER_report_row( $report_row, $metric_type, undef, $yop, $data_type )
269
                                );
270
                            }
271
                        }
272
                    }
273
                } else {
274
275
                    # Add one report row for each metric_type we're working with
276
                    foreach my $metric_type (@metric_types) {
277
                        push(
278
                            @report_body,
279
                            $self->_COUNTER_report_row( $report_row, $metric_type, undef, undef, $data_type )
280
                        );
281
                    }
282
                }
283
            }
284
        } elsif ($use_yop) {
285
            my %yops = map  { $_->{YOP} => 1 } @{ $report_row->{Attribute_Performance} };
286
            my @yops = sort { $b <=> $a } keys %yops;
287
            foreach my $yop (@yops) {
288
289
                if ($use_access_type) {
290
                    my @access_types = map { $_->{"Access_Type"} } @{ $report_row->{Attribute_Performance} };
291
                    foreach my $access_type (@access_types) {
292
293
                        # Add one report row for each metric_type we're working with
294
                        foreach my $metric_type (@metric_types) {
295
                            push(
296
                                @report_body,
297
                                $self->_COUNTER_report_row( $report_row, $metric_type, $access_type, $yop )
298
                            );
299
                        }
300
                    }
301
                } else {
302
303
                    # Add one report row for each metric_type we're working with
304
                    foreach my $metric_type (@metric_types) {
305
                        push( @report_body, $self->_COUNTER_report_row( $report_row, $metric_type, undef, $yop ) );
306
                    }
307
                }
308
            }
309
310
        } elsif ($use_access_type) {
311
            my @access_types = map { $_->{"Access_Type"} } @{ $report_row->{Attribute_Performance} };
312
            foreach my $access_type (@access_types) {
313
314
                # Add one report row for each metric_type we're working with
315
                foreach my $metric_type (@metric_types) {
316
                    push( @report_body, $self->_COUNTER_report_row( $report_row, $metric_type, $access_type ) );
317
                }
318
            }
319
        } else {
320
            foreach my $metric_type (@metric_types) {
321
                push( @report_body, $self->_COUNTER_report_row( $report_row, $metric_type ) );
322
            }
323
        }
324
325
    }
326
327
    return @report_body;
328
}
329
330
=head3 _COUNTER_title_report_row
331
332
Return a COUNTER title for the COUNTER titles report body
333
https://cop5.countermetrics.org/en/5.1.0.1/04-reports/03-title-reports.html#column-headings-elements
334
335
=cut
336
337
sub _COUNTER_title_report_row {
338
    my ( $self, $title_row, $metric_type, $total_usage, $monthly_usages, $access_type, $yop, $data_type ) = @_;
339
340
    my $header             = $self->{sushi}->{header};
341
    my $specific_fields    = $self->get_report_type_specific_fields( $header->{Report_ID} );
342
    my $access_type_to_use = $access_type ? $access_type : ( $title_row->{Access_Type} || "" );
343
    my $yop_to_use         = $yop         ? $yop         : ( $title_row->{YOP}         || "" );
344
    my $data_type_to_use   = $data_type   ? $data_type   : ( $title_row->{Data_Type}   || "" );
345
346
    return (
347
        [
348
            # Title
349
            $title_row->{Title} || "",
350
351
            # Publisher
352
            $title_row->{Publisher} || "",
353
354
            # Publisher_ID
355
            $self->_get_SUSHI_Type_Value( $title_row->{Publisher_ID}, "ISNI" ) || "",
356
357
            # Platform
358
            $title_row->{Platform} || "",
359
360
            # DOI
361
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "DOI" ) || "",
362
363
            # Proprietary_ID
364
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Proprietary" ) || "",
365
366
            # ISBN
367
            grep ( /ISBN/, @{$specific_fields} )
368
            ? ( $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "ISBN" ) || "" )
369
            : (),
370
371
            # Print_ISSN
372
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Print_ISSN" ) || "",
373
374
            # Online_ISSN
375
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Online_ISSN" ) || "",
376
377
            # URI - FIXME: What goes in URI?
378
            "",
379
380
            # Data_Type
381
            grep ( /Data_Type/, @{$specific_fields} ) ? $data_type_to_use : (),
382
383
            # YOP
384
            grep ( /YOP/, @{$specific_fields} ) ? $yop_to_use : (),
385
386
            # Access_Type
387
            grep ( /Access_Type/, @{$specific_fields} ) ? $access_type_to_use : (),
388
389
            # Metric_Type
390
            $metric_type,
391
392
            # Report_Period_Total
393
            $total_usage,
394
395
            # Monthly usage entries
396
            @{$monthly_usages}
397
        ]
398
    );
399
}
400
401
=head3 _COUNTER_titles_report_column_headings
402
403
Return titles report column headings
404
405
=cut
406
407
sub _COUNTER_titles_report_column_headings {
408
    my ($self) = @_;
409
410
    my $header          = $self->{sushi}->{header};
411
    my @month_headings  = $self->_get_usage_months( $header, 1 );
412
    my $specific_fields = $self->get_report_type_specific_fields( $header->{Report_ID} );
413
414
    return (
415
        [
416
            "Title",
417
            "Publisher",
418
            "Publisher_ID",
419
            "Platform",
420
            "DOI",
421
            "Proprietary_ID",
422
            grep ( /ISBN/, @{$specific_fields} ) ? ("ISBN") : (),
423
            "Print_ISSN",
424
            "Online_ISSN",
425
            "URI",
426
            grep ( /Data_Type/, @{$specific_fields} ) ? ("Data_Type") : (),
427
428
            #"Section_Type", #TODO: Only if requested (?)
429
            grep ( /YOP/,         @{$specific_fields} ) ? ("YOP")         : (),
430
            grep ( /Access_Type/, @{$specific_fields} ) ? ("Access_Type") : (),
431
432
            #"Access_Method", #TODO: Only if requested (?)
433
            "Metric_Type",
434
            "Reporting_Period_Total",
435
436
            # @month_headings in "Mmm-yyyy" format. TODO: Show unless Exclude_Monthly_Details=true
437
            @month_headings
438
        ]
439
    );
440
}
441
442
=head3 get_report_type_specific_fields
443
444
Returns the specific fields for a given report_type
445
446
=cut
447
448
sub get_report_type_specific_fields {
449
    my ( $self, $report_type ) = @_;
450
451
    my %report_type_map = (
452
        "TR_B1" => [ 'YOP', 'Data_Type', 'ISBN' ],
453
        "TR_B2" => [ 'YOP', 'Data_Type', 'ISBN' ],
454
        "TR_B3" => [ 'YOP', 'Data_Type', 'Access_Type', 'ISBN' ],
455
        "TR_J3" => ['Access_Type'],
456
        "TR_J4" => ['YOP'],
457
        "IR_A1" => [
458
            'Authors',            'Publication_Date', 'Article_Version',  'Print_ISSN', 'Online_ISSN', 'Parent_Title',
459
            'Parent_Authors',     'Parent_Article_Version', 'Parent_DOI', 'Parent_Proprietary_ID', 'Parent_Print_ISSN',
460
            'Parent_Online_ISSN', 'Parent_URI',             'Access_Type'
461
        ],
462
    );
463
464
    return $report_type_map{$report_type};
465
466
}
467
468
1;
(-)a/Koha/ERM/EUsage/CounterFile.pm (-15 / +47 lines)
Lines 85-90 Receive background_job_callbacks to be able to update job progress Link Here
85
sub store {
85
sub store {
86
    my ( $self, $background_job_callbacks ) = @_;
86
    my ( $self, $background_job_callbacks ) = @_;
87
87
88
    # DOCS:
89
    # COUNTER 5 CSV examples:
90
    # https://cop5.countermetrics.org/en/5.0.3/appendices/h-sample-counter-master-reports-and-standard-views.html
91
    # COUNTER 5.1 CSV examples:
92
    # https://cop5.projectcounter.org/en/5.1/appendices/g-sample-counter-reports-and-standard-views.html
93
88
    $self->_set_report_type_from_file;
94
    $self->_set_report_type_from_file;
89
95
90
    my $result = $self->SUPER::store;
96
    my $result = $self->SUPER::store;
Lines 227-233 sub _add_monthly_usage_entries { Link Here
227
233
228
    my $usage_data_provider = $self->get_usage_data_provider;
234
    my $usage_data_provider = $self->get_usage_data_provider;
229
    my $usage_object_info   = $self->_get_usage_object_id_hash($usage_object);
235
    my $usage_object_info   = $self->_get_usage_object_id_hash($usage_object);
230
    my $specific_fields     = Koha::ERM::EUsage::SushiCounter->get_report_type_specific_fields( $self->type );
236
    my $specific_fields     = Koha::ERM::EUsage::SushiCounter->get_report_type_specific_fields_by_release(
237
        $self->type,
238
        $self->get_COUNTER_report_release->{header_value}
239
    );
231
240
232
    $usage_object->monthly_usages(
241
    $usage_object->monthly_usages(
233
        [
242
        [
Lines 262-268 sub _add_yearly_usage_entries { Link Here
262
271
263
    my $usage_data_provider = $self->get_usage_data_provider;
272
    my $usage_data_provider = $self->get_usage_data_provider;
264
    my $usage_object_info   = $self->_get_usage_object_id_hash($usage_object);
273
    my $usage_object_info   = $self->_get_usage_object_id_hash($usage_object);
265
    my $specific_fields     = Koha::ERM::EUsage::SushiCounter->get_report_type_specific_fields( $self->type );
274
    my $specific_fields     = Koha::ERM::EUsage::SushiCounter->get_report_type_specific_fields_by_release(
275
        $self->type,
276
        $self->get_COUNTER_report_release->{header_value}
277
    );
266
278
267
    while ( my ( $year, $usage ) = each( %{$yearly_usages} ) ) {
279
    while ( my ( $year, $usage ) = each( %{$yearly_usages} ) ) {
268
280
Lines 303-323 A I <Koha::Exceptions::ERM::EUsage::CounterFile> exception is thrown Link Here
303
sub validate {
315
sub validate {
304
    my ($self) = @_;
316
    my ($self) = @_;
305
317
306
    open my $fh, "<", \$self->file_content or die;
318
    my $release = $self->get_COUNTER_report_release;
307
    my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1 } );
308
309
    $csv->column_names(qw( header_key header_value ));
310
    my @header_rows = $csv->getline_hr_all( $fh, 0, 12 );
311
    my @header      = $header_rows[0];
312
313
    my @release_row =
314
        map( $_->{header_key} eq 'Release' ? $_ : (), @{ $header[0] } );
315
    my $release = $release_row[0];
316
319
317
    # TODO: Validate that there is an empty row between header and body
320
    # TODO: Validate that there is an empty row between header and body
318
321
319
    Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease->throw
322
    Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease->throw
320
        if $release && $release->{header_value} != 5;
323
        if $release && ( $release->{header_value} != 5 && $release->{header_value} ne '5.1' );
321
324
322
}
325
}
323
326
Lines 344-349 sub _set_report_type_from_file { Link Here
344
    $self->type( $report->{header_value} );
347
    $self->type( $report->{header_value} );
345
}
348
}
346
349
350
=head3 get_COUNTER_report_release
351
352
Retrieves the COUNTER report release for the given file_content
353
354
=cut
355
356
sub get_COUNTER_report_release {
357
    my ($self) = @_;
358
359
    open my $fh, "<", \$self->file_content or die;
360
    my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1 } );
361
362
    $csv->column_names(qw( header_key header_value ));
363
    my @header_rows = $csv->getline_hr_all( $fh, 0, 12 );
364
    my @header      = $header_rows[0];
365
366
    my @release_row =
367
        map( $_->{header_key} eq 'Release' ? $_ : (), @{ $header[0] } );
368
    return $release_row[0];
369
}
370
347
=head3 _get_rows_from_COUNTER_file
371
=head3 _get_rows_from_COUNTER_file
348
372
349
Returns array of rows from COUNTER file
373
Returns array of rows from COUNTER file
Lines 356-362 sub _get_rows_from_COUNTER_file { Link Here
356
    open my $fh, "<", \$self->file_content or die;
380
    open my $fh, "<", \$self->file_content or die;
357
    my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1 } );
381
    my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1 } );
358
382
359
    my $header_columns = $csv->getline_all( $fh, 13, 1 );
383
    my $release = $self->get_COUNTER_report_release;
384
    $release = $release->{header_value};
385
386
    my $header_rows = $release eq '5.1' ? 14 : 13;
387
388
    my $header_columns = $csv->getline_all( $fh, $header_rows, 1 );
360
    $csv->column_names( @{$header_columns}[0] );
389
    $csv->column_names( @{$header_columns}[0] );
361
390
362
    # Get all rows from 14th onward
391
    # Get all rows from 14th onward
Lines 588-594 sub _add_usage_object_entry { Link Here
588
    my ( $self, $row ) = @_;
617
    my ( $self, $row ) = @_;
589
618
590
    my $usage_data_provider = $self->get_usage_data_provider;
619
    my $usage_data_provider = $self->get_usage_data_provider;
591
    my $specific_fields     = Koha::ERM::EUsage::SushiCounter->get_report_type_specific_fields( $self->type );
620
    my $specific_fields     = Koha::ERM::EUsage::SushiCounter->get_report_type_specific_fields_by_release(
621
        $self->type,
622
        $self->get_COUNTER_report_release->{header_value}
623
    );
592
624
593
    if ( $self->type =~ /PR/i ) {
625
    if ( $self->type =~ /PR/i ) {
594
        my $new_usage_platform = Koha::ERM::EUsage::UsagePlatform->new(
626
        my $new_usage_platform = Koha::ERM::EUsage::UsagePlatform->new(
(-)a/Koha/ERM/EUsage/SushiCounter.pm (-279 / +35 lines)
Lines 41-55 Koha::ERM::EUsage::SushiCounter - Koha SushiCounter Object class Link Here
41
sub new {
41
sub new {
42
    my ( $class, $params ) = @_;
42
    my ( $class, $params ) = @_;
43
43
44
    my $self = $class->SUPER::new;
44
    my $counter_release;
45
    $self->{sushi} = {
45
    if ( $params->{response}->{Report_Header}->{Release} eq "5" ) {
46
        require Koha::ERM::EUsage::COUNTER::5;
47
        $counter_release = Koha::ERM::EUsage::COUNTER::5->new;
48
    } elsif ( $params->{response}->{Report_Header}->{Release} eq "5.1" ) {
49
        require Koha::ERM::EUsage::COUNTER::5_1;
50
        $counter_release = Koha::ERM::EUsage::COUNTER::5_1->new;
51
    } else {
52
        Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease->throw(
53
            { counter_release => $params->{response}->{Report_Header}->{Release} } );
54
    }
55
56
    $counter_release->{sushi} = {
46
        header => $params->{response}->{Report_Header},
57
        header => $params->{response}->{Report_Header},
47
        body   => $params->{response}->{Report_Items}
58
        body   => $params->{response}->{Report_Items}
48
    };
59
    };
49
60
50
    #TODO: Handle empty $self->{sushi}->{body} here!
61
    #TODO: Handle empty $self->{sushi}->{body} here!
51
62
52
    return $self;
63
    return $counter_release;
53
}
64
}
54
65
55
=head3 get_COUNTER_from_SUSHI
66
=head3 get_COUNTER_from_SUSHI
Lines 92-138 sub _build_COUNTER_report_file { Link Here
92
103
93
}
104
}
94
105
95
=head3 _COUNTER_report_header
96
97
Return a COUNTER report header
98
https://cop5.projectcounter.org/en/5.0.2/04-reports/03-title-reports.html
99
100
=cut
101
102
sub _COUNTER_report_header {
103
    my ($self) = @_;
104
105
    my $header = $self->{sushi}->{header};
106
107
    my @metric_types_string = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "Metric_Type" );
108
109
    my $begin_date = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "Begin_Date" );
110
    my $end_date   = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, "End_Date" );
111
112
    return (
113
        [ Report_Name      => $header->{Report_Name}      || "" ],
114
        [ Report_ID        => $header->{Report_ID}        || "" ],
115
        [ Release          => $header->{Release}          || "" ],
116
        [ Institution_Name => $header->{Institution_Name} || "" ],
117
        [ Institution_ID => join( "; ", map( $_->{Type} . ":" . $_->{Value}, @{ $header->{Institution_ID} } ) ) || "" ],
118
        [ Metric_Types   => join( "; ", split( /\|/, $metric_types_string[0] ) )                                || "" ],
119
        [ Report_Filters => join( "; ", map( $_->{Name} . ":" . $_->{Value}, @{ $header->{Report_Filters} } ) ) || "" ],
120
121
        #TODO: Report_Attributes may need parsing, test this with a SUSHI response that provides it
122
        [ Report_Attributes => $header->{Report_Attributes} || "" ],
123
        [
124
            Exceptions => join(
125
                "; ", map( $_->{Code} . ": " . $_->{Message} . " (" . $_->{Data} . ")", @{ $header->{Exceptions} } )
126
                )
127
                || ""
128
        ],
129
        [ Reporting_Period => "Begin_Date=" . $begin_date . "; End_Date=" . $end_date ],
130
        [ Created          => $header->{Created} || "" ],
131
        [ Created_By       => $header->{Created_By} || "" ],
132
        [""]    #empty 13th line (COUNTER 5)
133
    );
134
}
135
136
=head3 _COUNTER_item_report_row
106
=head3 _COUNTER_item_report_row
137
107
138
Return a COUNTER item for the COUNTER items report body
108
Return a COUNTER item for the COUNTER items report body
Lines 274-344 sub _COUNTER_platform_report_row { Link Here
274
    );
244
    );
275
}
245
}
276
246
277
=head3 _COUNTER_title_report_row
278
279
Return a COUNTER title for the COUNTER titles report body
280
https://cop5.projectcounter.org/en/5.0.2/04-reports/03-title-reports.html#column-headings-elements
281
282
=cut
283
284
sub _COUNTER_title_report_row {
285
    my ( $self, $title_row, $metric_type, $total_usage, $monthly_usages ) = @_;
286
287
    my $header          = $self->{sushi}->{header};
288
    my $specific_fields = $self->get_report_type_specific_fields( $header->{Report_ID} );
289
290
    return (
291
        [
292
            # Title
293
            $title_row->{Title} || "",
294
295
            # Publisher
296
            $title_row->{Publisher} || "",
297
298
            # Publisher_ID
299
            $self->_get_SUSHI_Type_Value( $title_row->{Publisher_ID}, "ISNI" ) || "",
300
301
            # Platform
302
            $title_row->{Platform} || "",
303
304
            # DOI
305
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "DOI" ) || "",
306
307
            # Proprietary_ID
308
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Proprietary" ) || "",
309
310
            # ISBN
311
            grep ( /ISBN/, @{$specific_fields} )
312
            ? ( $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "ISBN" ) || "" )
313
            : (),
314
315
            # Print_ISSN
316
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Print_ISSN" ) || "",
317
318
            # Online_ISSN
319
            $self->_get_SUSHI_Type_Value( $title_row->{Item_ID}, "Online_ISSN" ) || "",
320
321
            # URI - FIXME: What goes in URI?
322
            "",
323
324
            # YOP
325
            grep ( /YOP/, @{$specific_fields} ) ? ( $title_row->{YOP} || "" ) : (),
326
327
            # Access_Type
328
            grep ( /Access_Type/, @{$specific_fields} ) ? ( $title_row->{Access_Type} || "" ) : (),
329
330
            # Metric_Type
331
            $metric_type,
332
333
            # Report_Period_Total
334
            $total_usage,
335
336
            # Monthly usage entries
337
            @{$monthly_usages}
338
        ]
339
    );
340
}
341
342
=head3 _COUNTER_report_row
247
=head3 _COUNTER_report_row
343
248
344
Return a COUNTER row for the COUNTER report body
249
Return a COUNTER row for the COUNTER report body
Lines 346-356 Return a COUNTER row for the COUNTER report body Link Here
346
=cut
251
=cut
347
252
348
sub _COUNTER_report_row {
253
sub _COUNTER_report_row {
349
    my ( $self, $report_row, $metric_type ) = @_;
254
    my ( $self, $report_row, $metric_type, $access_type, $yop, $data_type ) = @_;
350
255
351
    my $header = $self->{sushi}->{header};
256
    my $header = $self->{sushi}->{header};
352
257
353
    my ( $total_usage, @monthly_usages ) = $self->_get_COUNTER_row_usages( $report_row, $metric_type );
258
    my ( $total_usage, @monthly_usages ) = $self->_get_COUNTER_row_usages( $report_row, $metric_type, $access_type );
354
259
355
    if ( $header->{Report_ID} =~ /PR/i ) {
260
    if ( $header->{Report_ID} =~ /PR/i ) {
356
        return $self->_COUNTER_platform_report_row(
261
        return $self->_COUNTER_platform_report_row(
Lines 360-474 sub _COUNTER_report_row { Link Here
360
    } elsif ( $header->{Report_ID} =~ /DR/i ) {
265
    } elsif ( $header->{Report_ID} =~ /DR/i ) {
361
        return $self->_COUNTER_database_report_row( $report_row, $metric_type, $total_usage, \@monthly_usages );
266
        return $self->_COUNTER_database_report_row( $report_row, $metric_type, $total_usage, \@monthly_usages );
362
    } elsif ( $header->{Report_ID} =~ /IR/i ) {
267
    } elsif ( $header->{Report_ID} =~ /IR/i ) {
268
269
        #TODO: Send $access_type to _COUNTER_item_report_row like we're doing with _COUNTER_title_report_row
363
        return $self->_COUNTER_item_report_row( $report_row, $metric_type, $total_usage, \@monthly_usages );
270
        return $self->_COUNTER_item_report_row( $report_row, $metric_type, $total_usage, \@monthly_usages );
364
    } elsif ( $header->{Report_ID} =~ /TR/i ) {
271
    } elsif ( $header->{Report_ID} =~ /TR/i ) {
365
        return $self->_COUNTER_title_report_row( $report_row, $metric_type, $total_usage, \@monthly_usages );
272
        return $self->_COUNTER_title_report_row(
366
    }
273
            $report_row,  $metric_type, $total_usage, \@monthly_usages,
367
}
274
            $access_type, $yop,         $data_type
368
275
        );
369
=head3 _get_COUNTER_row_usages
370
371
Returns the total and monthly usages for a row
372
373
=cut
374
375
sub _get_COUNTER_row_usages {
376
    my ( $self, $row, $metric_type ) = @_;
377
378
    my @usage_months = $self->_get_usage_months( $self->{sushi}->{header} );
379
380
    my @usage_months_fields = ();
381
    my $count_total         = 0;
382
383
    foreach my $usage_month (@usage_months) {
384
        my $month_is_empty = 1;
385
386
        foreach my $performance ( @{ $row->{Performance} } ) {
387
            my $period             = $performance->{Period};
388
            my $period_usage_month = substr( $period->{Begin_Date}, 0, 7 );
389
390
            my $instances = $performance->{Instance};
391
            my @metric_type_count =
392
                map( $_->{Metric_Type} eq $metric_type ? $_->{Count} : (),
393
                @{$instances} );
394
395
            if ( $period_usage_month eq $usage_month && $metric_type_count[0] ) {
396
                push( @usage_months_fields, $metric_type_count[0] );
397
                $count_total += $metric_type_count[0];
398
                $month_is_empty = 0;
399
            }
400
        }
401
402
        if ($month_is_empty) {
403
            push( @usage_months_fields, 0 );
404
        }
405
    }
406
    return ( $count_total, @usage_months_fields );
407
}
408
409
=head3 _COUNTER_report_body
410
411
Return the COUNTER report body as an array
412
413
=cut
414
415
sub _COUNTER_report_body {
416
    my ($self) = @_;
417
418
    my $header = $self->{sushi}->{header};
419
    my $body   = $self->{sushi}->{body};
420
421
    my @report_body = ();
422
423
    foreach my $report_row ( @{$body} ) {
424
425
        my @metric_types = ();
426
427
        # Grab all metric_types this SUSHI result has statistics for
428
        foreach my $performance ( @{ $report_row->{Performance} } ) {
429
            my @SUSHI_metric_types =
430
                map( $_->{Metric_Type}, @{ $performance->{Instance} } );
431
432
            foreach my $sushi_metric_type (@SUSHI_metric_types) {
433
                push( @metric_types, $sushi_metric_type ) unless grep { $_ eq $sushi_metric_type } @metric_types;
434
            }
435
        }
436
437
        # Add one report row for each metric_type we're working with
438
        foreach my $metric_type (@metric_types) {
439
            push( @report_body, $self->_COUNTER_report_row( $report_row, $metric_type ) );
440
        }
441
    }
276
    }
442
443
    return @report_body;
444
}
445
446
=head3 _get_SUSHI_Name_Value
447
448
Returns "Value" of a given "Name"
449
450
=cut
451
452
sub _get_SUSHI_Name_Value {
453
    my ( $self, $item, $name ) = @_;
454
455
    my @value = map( $_->{Name} eq $name ? $_->{Value} : (), @{$item} );
456
457
    return $value[0];
458
}
459
460
=head3 _get_SUSHI_Type_Value
461
462
Returns "Value" of a given "Type"
463
464
=cut
465
466
sub _get_SUSHI_Type_Value {
467
    my ( $self, $item, $type ) = @_;
468
469
    my @value = map( $_->{Type} eq $type ? $_->{Value} : (), @{$item} );
470
471
    return $value[0];
472
}
277
}
473
278
474
=head3 _COUNTER_report_column_headings
279
=head3 _COUNTER_report_column_headings
Lines 617-661 sub _COUNTER_platforms_report_column_headings { Link Here
617
    );
422
    );
618
}
423
}
619
424
620
=head3 _COUNTER_titles_report_column_headings
425
=head3 get_report_type_specific_fields_by_release
621
426
622
Return titles report column headings
427
Returns the specific fields for a given report_type
623
428
624
=cut
429
=cut
625
430
626
sub _COUNTER_titles_report_column_headings {
431
sub get_report_type_specific_fields_by_release {
627
    my ($self) = @_;
432
    my ( $self, $report_type, $counter_release ) = @_;
628
629
    my $header          = $self->{sushi}->{header};
630
    my @month_headings  = $self->_get_usage_months( $header, 1 );
631
    my $specific_fields = $self->get_report_type_specific_fields( $header->{Report_ID} );
632
633
    return (
634
        [
635
            "Title",
636
            "Publisher",
637
            "Publisher_ID",
638
            "Platform",
639
            "DOI",
640
            "Proprietary_ID",
641
            grep ( /ISBN/, @{$specific_fields} ) ? ("ISBN") : (),
642
            "Print_ISSN",
643
            "Online_ISSN",
644
            "URI",
645
646
            #"Data_Type", #TODO: Only if requested (?)
647
            #"Section_Type", #TODO: Only if requested (?)
648
            grep ( /YOP/,         @{$specific_fields} ) ? ("YOP")         : (),
649
            grep ( /Access_Type/, @{$specific_fields} ) ? ("Access_Type") : (),
650
433
651
            #"Access_Method", #TODO: Only if requested (?)
434
    if ( $counter_release eq "5" ) {
652
            "Metric_Type",
435
        require Koha::ERM::EUsage::COUNTER::5;
653
            "Reporting_Period_Total",
436
        return Koha::ERM::EUsage::COUNTER::5->get_report_type_specific_fields($report_type);
654
437
    } elsif ( $counter_release eq "5.1" ) {
655
            # @month_headings in "Mmm-yyyy" format. TODO: Show unless Exclude_Monthly_Details=true
438
        require Koha::ERM::EUsage::COUNTER::5_1;
656
            @month_headings
439
        return Koha::ERM::EUsage::COUNTER::5_1->get_report_type_specific_fields($report_type);
657
        ]
440
    }
658
    );
659
}
441
}
660
442
661
=head3 _get_usage_months
443
=head3 _get_usage_months
Lines 672-682 sub _get_usage_months { Link Here
672
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
454
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
673
    );
455
    );
674
456
675
    my @begin_date  = map( $_->{Name} eq "Begin_Date" ? $_->{Value} : (), @{ $header->{Report_Filters} } );
457
    my @begin_date  = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, 'Begin_Date' );
676
    my $begin_month = substr( $begin_date[0], 5, 2 );
458
    my $begin_month = substr( $begin_date[0], 5, 2 );
677
    my $begin_year  = substr( $begin_date[0], 0, 4 );
459
    my $begin_year  = substr( $begin_date[0], 0, 4 );
678
460
679
    my @end_date  = map( $_->{Name} eq "End_Date" ? $_->{Value} : (), @{ $header->{Report_Filters} } );
461
    my @end_date  = $self->_get_SUSHI_Name_Value( $header->{Report_Filters}, 'End_Date' );
680
    my $end_month = substr( $end_date[0], 5, 2 );
462
    my $end_month = substr( $end_date[0], 5, 2 );
681
    my $end_year  = substr( $end_date[0], 0, 4 );
463
    my $end_year  = substr( $end_date[0], 0, 4 );
682
464
Lines 699-730 sub _get_usage_months { Link Here
699
    return @month_headings;
481
    return @month_headings;
700
}
482
}
701
483
702
=head3 get_report_type_specific_fields
703
704
Returns the specific fields for a given report_type
705
706
=cut
707
708
sub get_report_type_specific_fields {
709
    my ( $self, $report_type ) = @_;
710
711
    my %report_type_map = (
712
        "TR_B1" => [ 'YOP', 'ISBN' ],
713
        "TR_B2" => [ 'YOP', 'ISBN' ],
714
        "TR_B3" => [ 'YOP', 'Access_Type', 'ISBN' ],
715
        "TR_J3" => ['Access_Type'],
716
        "TR_J4" => ['YOP'],
717
        "IR_A1" => [
718
            'Authors', 'Publication_Date', 'Article_Version', 'Print_ISSN', 'Online_ISSN', 'Parent_Title',
719
            'Parent_Authors',     'Parent_Article_Version', 'Parent_DOI', 'Parent_Proprietary_ID', 'Parent_Print_ISSN',
720
            'Parent_Online_ISSN', 'Parent_URI',             'Access_Type'
721
        ],
722
    );
723
724
    return $report_type_map{$report_type};
725
726
}
727
728
=head3 _type
484
=head3 _type
729
485
730
=cut
486
=cut
(-)a/Koha/ERM/EUsage/UsageDataProvider.pm (-22 / +39 lines)
Lines 25-30 use LWP::UserAgent; Link Here
25
25
26
use Koha::Exceptions;
26
use Koha::Exceptions;
27
27
28
use Try::Tiny qw( catch try );
29
28
use base qw(Koha::Object);
30
use base qw(Koha::Object);
29
31
30
use Koha;
32
use Koha;
Lines 218-241 sub harvest_sushi { Link Here
218
    return if $self->_sushi_errors($result);
220
    return if $self->_sushi_errors($result);
219
221
220
    # Parse the SUSHI response
222
    # Parse the SUSHI response
221
    my $sushi_counter = Koha::ERM::EUsage::SushiCounter->new( { response => $result } );
223
    try {
222
    my $counter_file  = $sushi_counter->get_COUNTER_from_SUSHI;
224
        my $sushi_counter = Koha::ERM::EUsage::SushiCounter->new( { response => $result } );
223
225
        my $counter_file  = $sushi_counter->get_COUNTER_from_SUSHI;
224
    return if $self->_counter_file_size_too_large($counter_file);
225
226
226
    $self->counter_files(
227
        return if $self->_counter_file_size_too_large($counter_file);
227
        [
228
            {
229
                usage_data_provider_id => $self->erm_usage_data_provider_id,
230
                file_content           => $counter_file,
231
                date_uploaded          => POSIX::strftime( "%Y%m%d%H%M%S", localtime ),
232
228
233
                #TODO: add ".csv" to end of filename here
229
        $self->counter_files(
234
                filename => $self->name . "_" . $self->{report_type},
230
            [
235
            }
231
                {
236
        ]
232
                    usage_data_provider_id => $self->erm_usage_data_provider_id,
237
    );
233
                    file_content           => $counter_file,
234
                    date_uploaded          => POSIX::strftime( "%Y%m%d%H%M%S", localtime ),
238
235
236
                    #TODO: add ".csv" to end of filename here
237
                    filename => $self->name . "_" . $self->{report_type},
238
                }
239
            ]
240
        );
241
    } catch {
242
        if ( $_->isa('Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease') ) {
243
            $self->{job_callbacks}->{add_message_callback}->(
244
                {
245
                    type    => 'error',
246
                    message => 'COUNTER release ' . $_->{message}->{counter_release} . ' not supported',
247
                }
248
            ) if $self->{job_callbacks};
249
        }
250
    };
239
}
251
}
240
252
241
=head3 set_background_job_callbacks
253
=head3 set_background_job_callbacks
Lines 269-275 Tests the connection of the harvester to the SUSHI service and returns any alert Link Here
269
sub test_connection {
281
sub test_connection {
270
    my ($self) = @_;
282
    my ($self) = @_;
271
283
272
    my $url = _validate_url( $self->service_url, 'status' );
284
    my $url = $self->_validate_url( $self->service_url, 'status' );
273
    $url .= 'status';
285
    $url .= 'status';
274
    $url .= '?customer_id=' . $self->customer_id;
286
    $url .= '?customer_id=' . $self->customer_id;
275
    $url .= '&requestor_id=' . $self->requestor_id if $self->requestor_id;
287
    $url .= '&requestor_id=' . $self->requestor_id if $self->requestor_id;
Lines 384-390 sub _build_url_query { Link Here
384
            $self->erm_usage_data_provider_id;
396
            $self->erm_usage_data_provider_id;
385
    }
397
    }
386
398
387
    my $url = _validate_url( $self->service_url, 'harvest' );
399
    my $url = $self->_validate_url( $self->service_url, 'harvest' );
388
400
389
    $url .= lc $self->{report_type};
401
    $url .= lc $self->{report_type};
390
    $url .= '?customer_id=' . $self->customer_id;
402
    $url .= '?customer_id=' . $self->customer_id;
Lines 401-422 sub _build_url_query { Link Here
401
413
402
Checks whether the url ends in a trailing "/" and adds one if not
414
Checks whether the url ends in a trailing "/" and adds one if not
403
415
404
my $url = _validate_url($url, 'harvest')
416
my $url = $self->_validate_url($url, 'harvest')
405
417
406
$caller is either the harvest_sushi function ("harvest") or the test_connection function ("status")
418
$caller is either the harvest_sushi function ("harvest") or the test_connection function ("status")
407
419
408
=cut
420
=cut
409
421
410
sub _validate_url {
422
sub _validate_url {
411
    my ( $url, $caller ) = @_;
423
    my ( $self, $url, $caller ) = @_;
412
424
413
    if ( $caller eq 'harvest' ) {
425
    if ( $caller eq 'harvest' ) {
414
426
415
        # Not all urls will end in "/" - add one so they are standardised
416
        $url = _check_trailing_character($url);
427
        $url = _check_trailing_character($url);
417
428
418
        # All SUSHI report requests should be to the "/reports" endpoint
429
        # Default to 5.1 if anything other than '5'
419
        # Not all providers in the counter registry include this in their data so we need to check and add it
430
        my $report_release = $self->report_release eq '5' ? $self->report_release : '5.1';
431
432
        if ( $report_release eq '5.1' ) {
433
            my $reports_param = substr $url, -4;
434
            $url .= 'r51/' if $reports_param ne 'r51/';
435
        }
436
420
        my $reports_param = substr $url, -8;
437
        my $reports_param = substr $url, -8;
421
        $url .= 'reports/' if $reports_param ne 'reports/';
438
        $url .= 'reports/' if $reports_param ne 'reports/';
422
    } else {
439
    } else {
(-)a/Koha/Exceptions/ERM/EUsage/CounterFile.pm (-1 / +2 lines)
Lines 26-32 use Exception::Class ( Link Here
26
    },
26
    },
27
    'Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease' => {
27
    'Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease' => {
28
        isa         => 'Koha::Exceptions::ERM::EUsage::CounterFile',
28
        isa         => 'Koha::Exceptions::ERM::EUsage::CounterFile',
29
        description => 'This COUNTER release is not supported'
29
        description => 'This COUNTER release is not supported',
30
        fields      => ['counter_release'],
30
    }
31
    }
31
);
32
);
32
33
(-)a/Koha/REST/V1/ERM/EUsage/CounterRegistry.pm (-1 / +9 lines)
Lines 90-96 sub list { Link Here
90
    my @counter_5_supporting_platforms;
90
    my @counter_5_supporting_platforms;
91
    foreach my $platform (@$result) {
91
    foreach my $platform (@$result) {
92
        my $name_check = index( lc $platform->{name}, lc $search_string );
92
        my $name_check = index( lc $platform->{name}, lc $search_string );
93
        my @services   = grep { $_->{counter_release} eq '5' } @{ $platform->{sushi_services} };
93
94
        # TODO:
95
        # We should also consider COUNTER 5.1 here, but the COUNTER registry response is not great.
96
        # Visit the following URL:
97
        # <staff_url>/api/v1/erm/counter_registry?_per_page=-1&q={"name":"wiley"}
98
        # Notice the response comes back as the only sushi service being counter release 5,
99
        # but for all supported reports, both '5' and '5.1' are returned.
100
101
        my @services = grep { $_->{counter_release} eq '5' } @{ $platform->{sushi_services} };
94
        if (   scalar(@services) > 0
102
        if (   scalar(@services) > 0
95
            && $name_check != -1
103
            && $name_check != -1
96
            && scalar( @{ $platform->{reports} } ) > 0 )
104
            && scalar( @{ $platform->{reports} } ) > 0 )
(-)a/t/db_dependent/Koha/BackgroundJobs/ErmSushiHarvester.t (-2 / +18 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 3;
20
use Test::More tests => 5;
21
21
22
use Koha::Database;
22
use Koha::Database;
23
use Koha::BackgroundJobs;
23
use Koha::BackgroundJobs;
Lines 36-42 my $builder = t::lib::TestBuilder->new; Link Here
36
36
37
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
37
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
38
38
39
my $sushi_response_file_TR_J1      = dirname(__FILE__) . "/../../data/erm/eusage/TR_J1.json";
39
my $sushi_response_file_TR_J1      = dirname(__FILE__) . "/../../data/erm/eusage/COUNTER_5/TR_J1.json";
40
my $sushi_counter_5_response_TR_J1 = read_file($sushi_response_file_TR_J1);
40
my $sushi_counter_5_response_TR_J1 = read_file($sushi_response_file_TR_J1);
41
my $sushi_counter_report_TR_J1 =
41
my $sushi_counter_report_TR_J1 =
42
    Koha::ERM::EUsage::SushiCounter->new( { response => decode_json($sushi_counter_5_response_TR_J1) } );
42
    Koha::ERM::EUsage::SushiCounter->new( { response => decode_json($sushi_counter_5_response_TR_J1) } );
Lines 305-307 subtest 'enqueue_sushi_harvest_jobs_error_handling' => sub { Link Here
305
    $schema->storage->txn_rollback;
305
    $schema->storage->txn_rollback;
306
306
307
};
307
};
308
309
my $unsupported_sushi_response_file =
310
    dirname(__FILE__) . "/../../data/erm/eusage/UnsupportedCOUNTER/UnsupportedCOUNTER.json";
311
my $unsupported_sushi_counter_5_response_TR_J1 = read_file($unsupported_sushi_response_file);
312
313
eval {
314
    Koha::ERM::EUsage::SushiCounter->new( { response => decode_json($unsupported_sushi_counter_5_response_TR_J1) } );
315
};
316
if ($@) {
317
    isa_ok(
318
        $@, 'Koha::Exceptions::ERM::EUsage::CounterFile::UnsupportedRelease',
319
        'Unsupported release throws UnsupportedRelease exception'
320
    );
321
322
    is( $@->{message}->{counter_release}, 99, 'exception message has counter_release set to 99' );
323
}
(-)a/t/db_dependent/Koha/ERM/EUsage/COUNTER_5.1/CounterFile.t (+133 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::NoWarnings;
21
use Test::More tests => 3;
22
23
use Koha::Database;
24
use Koha::ERM::EUsage::CounterFile;
25
26
use JSON           qw( decode_json );
27
use File::Basename qw( dirname );
28
use File::Slurp;
29
30
use t::lib::Mocks;
31
use t::lib::TestBuilder;
32
use Test::MockModule;
33
34
my $schema  = Koha::Database->new->schema;
35
my $builder = t::lib::TestBuilder->new;
36
37
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
38
39
my $sushi_response_file_TR_J1       = dirname(__FILE__) . "/../../../../data/erm/eusage/COUNTER_5.1/TR_J1.json";
40
my $sushi_counter_51_response_TR_J1 = read_file($sushi_response_file_TR_J1);
41
my $sushi_counter_report_TR_J1 =
42
    Koha::ERM::EUsage::SushiCounter->new( { response => decode_json($sushi_counter_51_response_TR_J1) } );
43
44
subtest 'store' => sub {
45
46
    plan tests => 3;
47
48
    $schema->storage->txn_begin;
49
50
    my $patron = Koha::Patrons->search()->last;
51
    t::lib::Mocks::mock_userenv( { number => $patron->borrowernumber } );    # Is superlibrarian
52
53
    my $usage_data_provider = $builder->build_object(
54
        { class => 'Koha::ERM::EUsage::UsageDataProviders', value => { name => 'TestProvider' } } );
55
    $usage_data_provider->{report_type} = 'TR_J1';
56
57
    my $now_time = POSIX::strftime( "%Y%m%d%H%M%S", localtime );
58
59
    my $counter_file = Koha::ERM::EUsage::CounterFile->new(
60
        {
61
            usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id,
62
            file_content           => $sushi_counter_report_TR_J1->get_COUNTER_from_SUSHI,
63
            date_uploaded          => $now_time,
64
            filename               => $usage_data_provider->name . "_" . $usage_data_provider->{report_type},
65
        }
66
    )->store;
67
68
    # UsageTitles are added on CounterFile->store
69
    my $titles_rs = Koha::ERM::EUsage::UsageTitles->search(
70
        { usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id } );
71
72
    # MonthlyUsages are added on CounterFile->store
73
    my $mus_rs = Koha::ERM::EUsage::MonthlyUsages->search(
74
        { usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id } );
75
76
    # YearlyUsages are added on CounterFile->store
77
    my $yus_rs = Koha::ERM::EUsage::YearlyUsages->search(
78
        { usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id } );
79
80
    is( $titles_rs->count, 2,  '2 titles were added' );
81
    is( $mus_rs->count,    10, '10 monthly usages were added' );
82
    is( $yus_rs->count,    4,  '4 yearly usages were added' );
83
84
    $schema->storage->txn_rollback;
85
86
    #TODO: Test yop
87
    #TODO: acccess_type
88
89
};
90
91
subtest '_get_rows_from_COUNTER_file' => sub {
92
93
    plan tests => 4;
94
95
    $schema->storage->txn_begin;
96
97
    my $usage_data_provider = $builder->build_object(
98
        { class => 'Koha::ERM::EUsage::UsageDataProviders', value => { name => 'TestProvider' } } );
99
    $usage_data_provider->{report_type} = 'TR_J1';
100
101
    my $now_time = POSIX::strftime( "%Y%m%d%H%M%S", localtime );
102
103
    my $counter_file = $builder->build_object(
104
        {
105
            class => 'Koha::ERM::EUsage::CounterFiles',
106
            value => {
107
                usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id,
108
                file_content           => $sushi_counter_report_TR_J1->get_COUNTER_from_SUSHI,
109
                date_uploaded          => $now_time,
110
                filename               => $usage_data_provider->name . "_" . $usage_data_provider->{report_type},
111
            }
112
        }
113
    );
114
115
    my $counter_file_rows = $counter_file->_get_rows_from_COUNTER_file;
116
117
    is( ref $counter_file_rows, 'ARRAY', '_get_rows_from_COUNTER_file returns array' );
118
    is(
119
        scalar @{$counter_file_rows}, 4,
120
        '_get_rows_from_COUNTER_file returns correct number of rows'
121
    );
122
    is(
123
        @{$counter_file_rows}[0]->{Title}, 'Education and Training',
124
        'first and second report row is about the same title'
125
    );
126
    is(
127
        @{$counter_file_rows}[1]->{Title}, 'Education and Training',
128
        'first and second report row is about the same title'
129
    );
130
131
    $schema->storage->txn_rollback;
132
133
};
(-)a/t/db_dependent/Koha/ERM/EUsage/COUNTER_5.1/SushiCounter.t (+1031 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::NoWarnings;
21
use Test::More tests => 19;
22
23
use Koha::ERM::EUsage::SushiCounter;
24
use Koha::Database;
25
use JSON           qw( decode_json );
26
use File::Basename qw( dirname );
27
use File::Slurp;
28
29
use t::lib::TestBuilder;
30
31
my $schema  = Koha::Database->new->schema;
32
my $builder = t::lib::TestBuilder->new;
33
34
my $test_data_base_dir              = "/../../../../data/erm/eusage/COUNTER_5.1";
35
my $sushi_response_file_TR_J1       = dirname(__FILE__) . $test_data_base_dir . "/TR_J1.json";
36
my $sushi_counter_51_response_TR_J1 = decode_json( read_file($sushi_response_file_TR_J1) );
37
my $sushi_counter_TR_J1 =
38
    Koha::ERM::EUsage::SushiCounter->new( { version => '5.1', response => $sushi_counter_51_response_TR_J1 } );
39
40
subtest 'TR_J1 _COUNTER_report_header' => sub {
41
42
    plan tests => 43;
43
44
    my @report_header = $sushi_counter_TR_J1->_COUNTER_report_header;
45
46
    # Header row #1 - Report_Name
47
    is( $report_header[0][0], 'Report_Name',                          '1st row is report name' );
48
    is( $report_header[0][1], 'Journal Requests (Excluding OA_Gold)', '1st row is report name' );
49
    is( $report_header[0][2], undef,                                  '1st row is report name' );
50
51
    # Header row #2 - Report_ID
52
    is( $report_header[1][0], 'Report_ID', '2nd row is report name' );
53
    is( $report_header[1][1], 'TR_J1',     '2nd row is report name' );
54
    is( $report_header[1][2], undef,       '2nd row is report name' );
55
56
    # Header row #3 - Release
57
    is( $report_header[2][0], 'Release', '3rd row is counter release' );
58
    is( $report_header[2][1], '5.1',     '3rd row is counter release' );
59
    is( $report_header[2][2], undef,     '3rd row is counter release' );
60
61
    # Header row #4 - Institution_Name
62
    is( $report_header[3][0], 'Institution_Name', '4th row is institution name' );
63
    is( $report_header[3][1], 'Test Institution', '4th row is institution name' );
64
    is( $report_header[3][2], undef,              '4th row is institution name' );
65
66
    # Header row #5 - Institution_ID
67
    is( $report_header[4][0], 'Institution_ID', '5th row is institution id' );
68
    like( $report_header[4][1], qr/Proprietary:TInsti:EALTEST001|ISNI:0000000123456789/, '5th row is institution id' );
69
    is( $report_header[4][2], undef, '5th row is institution id' );
70
71
    # Header row #6 - Metric_Types
72
    is( $report_header[5][0], 'Metric_Types',                              '6th row is metric types' );
73
    is( $report_header[5][1], 'Total_Item_Requests; Unique_Item_Requests', '6th row is metric types' );
74
    is( $report_header[5][2], undef,                                       '6th row is metric types' );
75
76
    # Header row #7 - Report_Filters
77
    is( $report_header[6][0], 'Report_Filters', '7th row is report filters' );
78
    like( $report_header[6][1], qr/End_Date:2022-09-30/,   '7th row is report filters' );
79
    like( $report_header[6][1], qr/Access_Method:Regular/, '7th row is report filters' );
80
    like(
81
        $report_header[6][1], qr/Metric_Type:Total_Item_Requests\|Unique_Item_Requests/,
82
        '7th row is report filters'
83
    );
84
    like( $report_header[6][1], qr/Data_Type:Journal/,      '7th row is report filters' );
85
    like( $report_header[6][1], qr/Begin_Date:2021-09-01/,  '7th row is report filters' );
86
    like( $report_header[6][1], qr/Access_Type:Controlled/, '7th row is report filters' );
87
    is( $report_header[6][2], undef, '7th row is report filters' );
88
89
    # Header row #8 - Report_Attributes
90
    is( $report_header[7][0], 'Report_Attributes', '8th row is report attributes' );
91
    is( $report_header[7][1], '',                  '8th row is report attributes' );
92
    is( $report_header[7][2], undef,               '8th row is report attributes' );
93
94
    # Header row #9 - Exceptions
95
    is( $report_header[8][0], 'Exceptions', '9th row is exceptions' );
96
    is( $report_header[8][1], '',           '9th row is exceptions' );
97
    is( $report_header[8][2], undef,        '9th row is exceptions' );
98
99
    # Header row #10 - Reporting_Period
100
    is( $report_header[9][0], 'Reporting_Period',                           '10th row is reporting period' );
101
    is( $report_header[9][1], 'Begin_Date=2021-09-01; End_Date=2022-09-30', '10th row is reporting period' );
102
    is( $report_header[9][2], undef,                                        '10th row is reporting period' );
103
104
    # Header row #11 - Created
105
    is( $report_header[10][0], 'Created',              '11th row is created' );
106
    is( $report_header[10][1], '2023-08-29T07:11:41Z', '11th row is created' );
107
    is( $report_header[10][2], undef,                  '11th row is created' );
108
109
    # Header row #12 - Created
110
    is( $report_header[11][0], 'Created_By',        '12th row is created by' );
111
    is( $report_header[11][1], 'Test Systems Inc.', '12th row is created by' );
112
    is( $report_header[11][2], undef,               '12th row is created by' );
113
114
    # Header row #13 - Registry_Record
115
    is( $report_header[12][0], 'Registry_Record', '13th row is empty' );
116
117
    # Header row #14 - This needs to be empty
118
    is( $report_header[13][0], '', '14th row is empty' );
119
};
120
121
subtest 'TR_J1 _COUNTER_report_column_headings' => sub {
122
123
    plan tests => 19;
124
125
    my @report_column_headings = $sushi_counter_TR_J1->_COUNTER_report_column_headings;
126
127
    # Standard TR_J1 column headings
128
    is( $report_column_headings[0][0],  'Title',                  '1st column heading is title' );
129
    is( $report_column_headings[0][1],  'Publisher',              '2nd column heading is publisher' );
130
    is( $report_column_headings[0][2],  'Publisher_ID',           '3rd column heading is publisher ID' );
131
    is( $report_column_headings[0][3],  'Platform',               '4th column heading is platform' );
132
    is( $report_column_headings[0][4],  'DOI',                    '5th column heading is DOI' );
133
    is( $report_column_headings[0][5],  'Proprietary_ID',         '6th column heading is proprietary ID' );
134
    is( $report_column_headings[0][6],  'Print_ISSN',             '7th column heading is print ISSN' );
135
    is( $report_column_headings[0][7],  'Online_ISSN',            '8th column heading is online ISSN' );
136
    is( $report_column_headings[0][8],  'URI',                    '9th column heading is URI' );
137
    is( $report_column_headings[0][9],  'Metric_Type',            '10th column heading is metric type' );
138
    is( $report_column_headings[0][10], 'Reporting_Period_Total', '11th column heading is reporting period total' );
139
140
    # Months column headings
141
    is( $report_column_headings[0][11], 'Sep 2021', '12th column is month column heading' );
142
    is( $report_column_headings[0][12], 'Oct 2021', '13th column is month column heading' );
143
    is( $report_column_headings[0][13], 'Nov 2021', '14th column is month column heading' );
144
    is( $report_column_headings[0][14], 'Dec 2021', '15th column is month column heading' );
145
    is( $report_column_headings[0][15], 'Jan 2022', '16th column is month column heading' );
146
    is( $report_column_headings[0][16], 'Feb 2022', '17th column is month column heading' );
147
148
    # ... period is september 2021 to september 2022, i.e. 13 months
149
    is( $report_column_headings[0][23], 'Sep 2022', '23rd column is the last month column heading' );
150
    is( $report_column_headings[0][24], undef,      '24th column is empty, no more months' );
151
};
152
153
subtest 'TR_J1 _COUNTER_report_body' => sub {
154
155
    plan tests => 16;
156
157
    my @report_body = $sushi_counter_TR_J1->_COUNTER_report_body;
158
159
    # The same title is sequential but for different metric types
160
    is( $report_body[0][0], 'Education and Training', 'same title, different metric type' );
161
    is( $report_body[1][0], 'Education and Training', 'same title, different metric type' );
162
    is( $report_body[0][9], 'Total_Item_Requests',    'same title, different metric type' );
163
    is( $report_body[1][9], 'Unique_Item_Requests',   'same title, different metric type' );
164
165
    # The data is in the correct column
166
    is( $report_body[2][0],  'Test Journal',            '1st column is title' );
167
    is( $report_body[2][1],  'Test Publisher',          '2nd column is publisher' );
168
    is( $report_body[2][2],  '0000000123456789',        '3rd column heading is publisher ID' );
169
    is( $report_body[2][3],  'Unit Test Library',       '4th column is platform' );
170
    is( $report_body[2][4],  '10.1002/(ISSN)1111-2222', '5th column is DOI' );
171
    is( $report_body[2][5],  'TInsti:ABC1',             '6th column is proprietary ID' );
172
    is( $report_body[2][6],  '7777-8888',               '7th column is print ISSN' );
173
    is( $report_body[2][7],  '5555-6666',               '8th column is online ISSN' );
174
    is( $report_body[2][8],  '',                        '9th column is URI' );
175
    is( $report_body[2][9],  'Total_Item_Requests',     '10th column is metric type' );
176
    is( $report_body[2][10], 2,                         '11th column is reporting period total' );
177
178
    # The period total is the sum of all the month columns
179
    my $stats_total = 0;
180
    for ( my $i = 11 ; $i < 24 ; $i++ ) {
181
        $stats_total += $report_body[0][$i];
182
    }
183
    is(
184
        $report_body[0][10], $stats_total,
185
        'Reporting period total matches the sum of all the monthly usage statistics'
186
    );
187
};
188
189
my $sushi_response_file_TR_J2       = dirname(__FILE__) . $test_data_base_dir . "/TR_J2.json";
190
my $sushi_counter_51_response_TR_J2 = decode_json( read_file($sushi_response_file_TR_J2) );
191
my $sushi_counter_TR_J2 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_51_response_TR_J2 } );
192
193
subtest 'TR_J2 _COUNTER_report_header' => sub {
194
195
    plan tests => 42;
196
197
    my @report_header = $sushi_counter_TR_J2->_COUNTER_report_header;
198
199
    # Header row #1 - Report_Name
200
    is( $report_header[0][0], 'Report_Name',           '1st row is report name' );
201
    is( $report_header[0][1], 'Journal Access Denied', '1st row is report name' );
202
    is( $report_header[0][2], undef,                   '1st row is report name' );
203
204
    # Header row #2 - Report_ID
205
    is( $report_header[1][0], 'Report_ID', '2nd row is report name' );
206
    is( $report_header[1][1], 'TR_J2',     '2nd row is report name' );
207
    is( $report_header[1][2], undef,       '2nd row is report name' );
208
209
    # Header row #3 - Release
210
    is( $report_header[2][0], 'Release', '3rd row is counter release' );
211
    is( $report_header[2][1], '5.1',     '3rd row is counter release' );
212
    is( $report_header[2][2], undef,     '3rd row is counter release' );
213
214
    # Header row #4 - Institution_Name
215
    is( $report_header[3][0], 'Institution_Name',   '4th row is institution name' );
216
    is( $report_header[3][1], 'Sample Institution', '4th row is institution name' );
217
    is( $report_header[3][2], undef,                '4th row is institution name' );
218
219
    # Header row #5 - Institution_ID
220
    is( $report_header[4][0], 'Institution_ID',        '5th row is institution id' );
221
    is( $report_header[4][1], 'ISNI:1234123412341234', '5th row is institution id' );
222
    is( $report_header[4][2], undef,                   '5th row is institution id' );
223
224
    # Header row #6 - Metric_Types
225
    is( $report_header[5][0], 'Metric_Types',               '6th row is metric types' );
226
    is( $report_header[5][1], 'Limit_Exceeded; No_License', '6th row is metric types' );
227
    is( $report_header[5][2], undef,                        '6th row is metric types' );
228
229
    # Header row #7 - Report_Filters
230
    is( $report_header[6][0], 'Report_Filters', '7th row is report filters' );
231
    like( $report_header[6][1], qr/Metric_Type:Limit_Exceeded\|No_License/, '7th row is report filters' );
232
    like( $report_header[6][1], qr/Begin_Date:2022-01-01/,                  '7th row is report filters' );
233
    like( $report_header[6][1], qr/End_Date:2022-03-31/,                    '7th row is report filters' );
234
    like( $report_header[6][1], qr/Access_Method:Regular/,                  '7th row is report filters' );
235
    like( $report_header[6][1], qr/Data_Type:Journal/,                      '7th row is report filters' );
236
237
    is( $report_header[6][2], undef, '7th row is report filters' );
238
239
    # Header row #8 - Report_Attributes
240
    is( $report_header[7][0], 'Report_Attributes', '8th row is report attributes' );
241
    is( $report_header[7][1], '',                  '8th row is report attributes' );
242
    is( $report_header[7][2], undef,               '8th row is report attributes' );
243
244
    # Header row #9 - Exceptions
245
    is( $report_header[8][0], 'Exceptions', '9th row is exceptions' );
246
    is( $report_header[8][1], '',           '9th row is exceptions' );
247
    is( $report_header[8][2], undef,        '9th row is exceptions' );
248
249
    # Header row #10 - Reporting_Period
250
    is( $report_header[9][0], 'Reporting_Period',                           '10th row is reporting period' );
251
    is( $report_header[9][1], 'Begin_Date=2022-01-01; End_Date=2022-03-31', '10th row is reporting period' );
252
    is( $report_header[9][2], undef,                                        '10th row is reporting period' );
253
254
    # Header row #11 - Created
255
    is( $report_header[10][0], 'Created',              '11th row is created' );
256
    is( $report_header[10][1], '2023-02-15T09:11:12Z', '11th row is created' );
257
    is( $report_header[10][2], undef,                  '11th row is created' );
258
259
    # Header row #12 - Created
260
    is( $report_header[11][0], 'Created_By',       '12th row is created by' );
261
    is( $report_header[11][1], 'Sample Publisher', '12th row is created by' );
262
    is( $report_header[11][2], undef,              '12th row is created by' );
263
264
    # Header row #13 - Registry_Record
265
    is( $report_header[12][0], 'Registry_Record', '13th row is Registry_Record' );
266
267
    # Header row #14 - This needs to be empty
268
    is( $report_header[13][0], '', '14th row is empty' );
269
};
270
271
subtest 'TR_J2 _COUNTER_report_column_headings' => sub {
272
273
    plan tests => 15;
274
275
    my @report_column_headings = $sushi_counter_TR_J2->_COUNTER_report_column_headings;
276
277
    # Standard TR_J2 column headings
278
    is( $report_column_headings[0][0],  'Title',                  '1st column heading is title' );
279
    is( $report_column_headings[0][1],  'Publisher',              '2nd column heading is publisher' );
280
    is( $report_column_headings[0][2],  'Publisher_ID',           '3rd column heading is publisher ID' );
281
    is( $report_column_headings[0][3],  'Platform',               '4th column heading is platform' );
282
    is( $report_column_headings[0][4],  'DOI',                    '5th column heading is DOI' );
283
    is( $report_column_headings[0][5],  'Proprietary_ID',         '6th column heading is proprietary ID' );
284
    is( $report_column_headings[0][6],  'Print_ISSN',             '7th column heading is print ISSN' );
285
    is( $report_column_headings[0][7],  'Online_ISSN',            '8th column heading is online ISSN' );
286
    is( $report_column_headings[0][8],  'URI',                    '9th column heading is URI' );
287
    is( $report_column_headings[0][9],  'Metric_Type',            '10th column heading is metric type' );
288
    is( $report_column_headings[0][10], 'Reporting_Period_Total', '11th column heading is reporting period total' );
289
290
    # Months column headings
291
    is( $report_column_headings[0][11], 'Jan 2022', '12th column is month column heading' );
292
    is( $report_column_headings[0][12], 'Feb 2022', '13th column is another month column heading' );
293
    is( $report_column_headings[0][13], 'Mar 2022', '14th column is the last month column heading' );
294
    is( $report_column_headings[0][14], undef,      '15th column is empty, no more months' );
295
};
296
297
subtest 'TR_J2 _COUNTER_report_body' => sub {
298
299
    plan tests => 16;
300
301
    my @report_body = $sushi_counter_TR_J2->_COUNTER_report_body;
302
303
    # The same title is sequential but for different metric types
304
    is( $report_body[0][0], 'Title 3',        'same title, different metric type' );
305
    is( $report_body[1][0], 'Title 3',        'same title, same metric type' );
306
    is( $report_body[0][9], 'Limit_Exceeded', '1st title, different metric_type' );
307
    is( $report_body[1][9], 'No_License',     '1sd title, different metric_type' );
308
309
    # The data is in the correct column
310
    is( $report_body[2][0],  'Another title',     '1st column is title' );
311
    is( $report_body[2][1],  'Another publisher', '2nd column is publisher' );
312
    is( $report_body[2][2],  '4321432143214321',  '3rd column is publisher ID and shows because there is ISNI' );
313
    is( $report_body[2][3],  'Platform 1',        '4th column is platform' );
314
    is( $report_body[2][4],  '10.9999/xxxxt03',   '5th column is DOI' );
315
    is( $report_body[2][5],  'P1:T03',            '6th column is proprietary ID' );
316
    is( $report_body[2][6],  '',                  '7th column is print ISSN' );
317
    is( $report_body[2][7],  '1234-4321',         '8th column is online ISSN' );
318
    is( $report_body[2][8],  '',                  '9th column is URI' );
319
    is( $report_body[2][9],  'Limit_Exceeded',    '10th column is metric type' );
320
    is( $report_body[2][10], 388,                 '11th column is reporting period total' );
321
322
    # The period total is the sum of all the month columns
323
    my $stats_total = 0;
324
    for ( my $i = 11 ; $i < 14 ; $i++ ) {
325
        $stats_total += $report_body[0][$i];
326
    }
327
328
    is(
329
        $report_body[0][10], $stats_total,
330
        'Reporting period total matches the sum of all the monthly usage statistics'
331
    );
332
};
333
334
my $sushi_response_file_TR_J3       = dirname(__FILE__) . $test_data_base_dir . "/TR_J3.json";
335
my $sushi_counter_51_response_TR_J3 = decode_json( read_file($sushi_response_file_TR_J3) );
336
my $sushi_counter_TR_J3 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_51_response_TR_J3 } );
337
338
subtest 'TR_J3 _COUNTER_report_header' => sub {
339
340
    plan tests => 42;
341
342
    my @report_header = $sushi_counter_TR_J3->_COUNTER_report_header;
343
344
    # Header row #1 - Report_Name
345
    is( $report_header[0][0], 'Report_Name',                  '1st row is report name' );
346
    is( $report_header[0][1], 'Journal Usage by Access Type', '1st row is report name' );
347
    is( $report_header[0][2], undef,                          '1st row is report name' );
348
349
    # Header row #2 - Report_ID
350
    is( $report_header[1][0], 'Report_ID', '2nd row is report name' );
351
    is( $report_header[1][1], 'TR_J3',     '2nd row is report name' );
352
    is( $report_header[1][2], undef,       '2nd row is report name' );
353
354
    # Header row #3 - Release
355
    is( $report_header[2][0], 'Release', '3rd row is counter release' );
356
    is( $report_header[2][1], '5.1',     '3rd row is counter release' );
357
    is( $report_header[2][2], undef,     '3rd row is counter release' );
358
359
    # Header row #4 - Institution_Name
360
    is( $report_header[3][0], 'Institution_Name',   '4th row is institution name' );
361
    is( $report_header[3][1], 'Sample Institution', '4th row is institution name' );
362
    is( $report_header[3][2], undef,                '4th row is institution name' );
363
364
    # Header row #5 - Institution_ID
365
    is( $report_header[4][0], 'Institution_ID',        '5th row is institution id' );
366
    is( $report_header[4][1], 'ISNI:1234123412341234', '5th row is institution id' );
367
    is( $report_header[4][2], undef,                   '5th row is institution id' );
368
369
    # Header row #6 - Metric_Types
370
    is( $report_header[5][0], 'Metric_Types', '6th row is metric types' );
371
    is(
372
        $report_header[5][1],
373
        'Total_Item_Investigations; Total_Item_Requests; Unique_Item_Investigations; Unique_Item_Requests',
374
        '6th row is metric types'
375
    );
376
    is( $report_header[5][2], undef, '6th row is metric types' );
377
378
    # Header row #7 - Report_Filters
379
    is( $report_header[6][0], 'Report_Filters', '7th row is report filters' );
380
    like(
381
        $report_header[6][1],
382
        qr/Metric_Type:Total_Item_Investigations\|Total_Item_Requests\|Unique_Item_Investigations\|Unique_Item_Requests/,
383
        '7th row is report filters'
384
    );
385
    like( $report_header[6][1], qr/Access_Method:Regular/, '7th row is report filters' );
386
    like( $report_header[6][1], qr/End_Date:2022-03-31/,   '7th row is report filters' );
387
    like( $report_header[6][1], qr/Data_Type:Journal/,     '7th row is report filters' );
388
    like( $report_header[6][1], qr/Begin_Date:2022-01-01/, '7th row is report filters' );
389
390
    is( $report_header[6][2], undef, '7th row is report filters' );
391
392
    # Header row #8 - Report_Attributes
393
    is( $report_header[7][0], 'Report_Attributes', '8th row is report attributes' );
394
    is( $report_header[7][1], '',                  '8th row is report attributes' );
395
    is( $report_header[7][2], undef,               '8th row is report attributes' );
396
397
    # Header row #9 - Exceptions
398
    is( $report_header[8][0], 'Exceptions', '9th row is exceptions' );
399
    is( $report_header[8][1], '',           '9th row is exceptions' );
400
    is( $report_header[8][2], undef,        '9th row is exceptions' );
401
402
    # Header row #10 - Reporting_Period
403
    is( $report_header[9][0], 'Reporting_Period',                           '10th row is reporting period' );
404
    is( $report_header[9][1], 'Begin_Date=2022-01-01; End_Date=2022-03-31', '10th row is reporting period' );
405
    is( $report_header[9][2], undef,                                        '10th row is reporting period' );
406
407
    # Header row #11 - Created
408
    is( $report_header[10][0], 'Created',              '11th row is created' );
409
    is( $report_header[10][1], '2023-02-15T09:11:12Z', '11th row is created' );
410
    is( $report_header[10][2], undef,                  '11th row is created' );
411
412
    # Header row #12 - Created
413
    is( $report_header[11][0], 'Created_By',       '12th row is created by' );
414
    is( $report_header[11][1], 'Sample Publisher', '12th row is created by' );
415
    is( $report_header[11][2], undef,              '12th row is created by' );
416
417
    # Header row #13 - Registry_Record
418
    is( $report_header[12][0], 'Registry_Record', '13th row is Registry_Record' );
419
420
    # Header row #14 - This needs to be empty
421
    is( $report_header[13][0], '', '14th row is empty' );
422
};
423
424
subtest 'TR_J3 _COUNTER_report_column_headings' => sub {
425
426
    plan tests => 16;
427
428
    my @report_column_headings = $sushi_counter_TR_J3->_COUNTER_report_column_headings;
429
430
    # Standard TR_J3 column headings
431
    is( $report_column_headings[0][0],  'Title',                  '1st column heading is title' );
432
    is( $report_column_headings[0][1],  'Publisher',              '2nd column heading is publisher' );
433
    is( $report_column_headings[0][2],  'Publisher_ID',           '3rd column heading is publisher ID' );
434
    is( $report_column_headings[0][3],  'Platform',               '4th column heading is platform' );
435
    is( $report_column_headings[0][4],  'DOI',                    '5th column heading is DOI' );
436
    is( $report_column_headings[0][5],  'Proprietary_ID',         '6th column heading is proprietary ID' );
437
    is( $report_column_headings[0][6],  'Print_ISSN',             '7th column heading is print ISSN' );
438
    is( $report_column_headings[0][7],  'Online_ISSN',            '8th column heading is online ISSN' );
439
    is( $report_column_headings[0][8],  'URI',                    '9th column heading is URI' );
440
    is( $report_column_headings[0][9],  'Access_Type',            '10th column heading is access type' );
441
    is( $report_column_headings[0][10], 'Metric_Type',            '11th column heading is access type' );
442
    is( $report_column_headings[0][11], 'Reporting_Period_Total', '12th column heading is reporting period total' );
443
444
    # Months column headings
445
    is( $report_column_headings[0][12], 'Jan 2022', '12th column is month column heading' );
446
    is( $report_column_headings[0][13], 'Feb 2022', '13th column is another month column heading' );
447
    is( $report_column_headings[0][14], 'Mar 2022', '13th column is the last month column heading' );
448
    is( $report_column_headings[0][25], undef,      '14th column is empty, no more months' );
449
};
450
451
subtest 'TR_J3 _COUNTER_report_body' => sub {
452
453
    plan tests => 25;
454
455
    my @report_body = $sushi_counter_TR_J3->_COUNTER_report_body;
456
457
    # The same title is sequential but for different metric types
458
    is( $report_body[0][0],  'Title 3',                    'same title, different metric type' );
459
    is( $report_body[1][0],  'Title 3',                    'same title, different metric type' );
460
    is( $report_body[2][0],  'Title 3',                    'same title, different metric type' );
461
    is( $report_body[3][0],  'Title 3',                    'same title, different metric type' );
462
    is( $report_body[0][9],  'Controlled',                 'same title, same access_type' );
463
    is( $report_body[1][9],  'Controlled',                 'same title, same access_type' );
464
    is( $report_body[2][9],  'Controlled',                 'same title, same access_type' );
465
    is( $report_body[3][9],  'Controlled',                 'same title, same access_type' );
466
    is( $report_body[0][10], 'Total_Item_Investigations',  'same title, different metric type' );
467
    is( $report_body[1][10], 'Total_Item_Requests',        'same title, different metric type' );
468
    is( $report_body[2][10], 'Unique_Item_Investigations', 'same title, different metric type' );
469
    is( $report_body[3][10], 'Unique_Item_Requests',       'same title, different metric type' );
470
471
    # The data is in the correct column
472
    is( $report_body[2][0],  'Title 3',                    '1st column is title' );
473
    is( $report_body[2][1],  'Sample Publisher',           '2nd column is publisher' );
474
    is( $report_body[2][2],  '4321432143214321',           '3rd column is publisher ID' );
475
    is( $report_body[2][3],  'Platform 1',                 '4th column is platform' );
476
    is( $report_body[2][4],  '10.9999/xxxxt03',            '5th column is DOI' );
477
    is( $report_body[2][5],  'P1:T03',                     '6th column is proprietary ID' );
478
    is( $report_body[2][6],  '',                           '7th column is print ISSN' );
479
    is( $report_body[2][7],  '1234-4321',                  '8th column is online ISSN' );
480
    is( $report_body[2][8],  '',                           '9th column is URI' );
481
    is( $report_body[2][9],  'Controlled',                 '10th column is access type' );
482
    is( $report_body[2][10], 'Unique_Item_Investigations', '11th column is metric type' );
483
    is( $report_body[2][11], 1602,                         '12th column is reporting period total' );    # 608+618+376
484
485
    # The period total is the sum of all the month columns
486
    my $stats_total = 0;
487
    for ( my $i = 12 ; $i < 15 ; $i++ ) {
488
        $stats_total += $report_body[0][$i];
489
    }
490
    is(
491
        $report_body[0][11], $stats_total,
492
        'Reporting period total matches the sum of all the monthly usage statistics'
493
    );
494
};
495
496
my $sushi_response_file_TR_J4       = dirname(__FILE__) . $test_data_base_dir . "/TR_J4.json";
497
my $sushi_counter_51_response_TR_J4 = decode_json( read_file($sushi_response_file_TR_J4) );
498
my $sushi_counter_TR_J4 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_51_response_TR_J4 } );
499
500
subtest 'TR_J4 _COUNTER_report_header' => sub {
501
502
    plan tests => 43;
503
504
    my @report_header = $sushi_counter_TR_J4->_COUNTER_report_header;
505
506
    # Header row #1 - Report_Name
507
    is( $report_header[0][0], 'Report_Name',                          '1st row is report name' );
508
    is( $report_header[0][1], 'Journal Requests by YOP (Controlled)', '1st row is report name' );
509
    is( $report_header[0][2], undef,                                  '1st row is report name' );
510
511
    # Header row #2 - Report_ID
512
    is( $report_header[1][0], 'Report_ID', '2nd row is report name' );
513
    is( $report_header[1][1], 'TR_J4',     '2nd row is report name' );
514
    is( $report_header[1][2], undef,       '2nd row is report name' );
515
516
    # Header row #3 - Release
517
    is( $report_header[2][0], 'Release', '3rd row is counter release' );
518
    is( $report_header[2][1], '5.1',     '3rd row is counter release' );
519
    is( $report_header[2][2], undef,     '3rd row is counter release' );
520
521
    # Header row #4 - Institution_Name
522
    is( $report_header[3][0], 'Institution_Name',   '4th row is institution name' );
523
    is( $report_header[3][1], 'Sample Institution', '4th row is institution name' );
524
    is( $report_header[3][2], undef,                '4th row is institution name' );
525
526
    # Header row #5 - Institution_ID
527
    is( $report_header[4][0], 'Institution_ID',        '5th row is institution id' );
528
    is( $report_header[4][1], 'ISNI:1234123412341234', '5th row is institution id' );
529
    is( $report_header[4][2], undef,                   '5th row is institution id' );
530
531
    # Header row #6 - Metric_Types
532
    is( $report_header[5][0], 'Metric_Types', '6th row is metric types' );
533
    is(
534
        $report_header[5][1],
535
        'Total_Item_Requests; Unique_Item_Requests',
536
        '6th row is metric types'
537
    );
538
    is( $report_header[5][2], undef, '6th row is metric types' );
539
540
    # Header row #7 - Report_Filters
541
    is( $report_header[6][0], 'Report_Filters', '7th row is report filters' );
542
    like( $report_header[6][1], qr/Metric_Type:Total_Item_Requests|Unique_Item_Requests/, '7th row is report filters' );
543
    like( $report_header[6][1], qr/Access_Method:Regular/,                                '7th row is report filters' );
544
    like( $report_header[6][1], qr/Begin_Date:2022-01-01/,                                '7th row is report filters' );
545
    like( $report_header[6][1], qr/Access_Type:Controlled/,                               '7th row is report filters' );
546
    like( $report_header[6][1], qr/End_Date:2022-03-31/,                                  '7th row is report filters' );
547
    like( $report_header[6][1], qr/Data_Type:Journal/,                                    '7th row is report filters' );
548
549
    is( $report_header[6][2], undef, '7th row is report filters' );
550
551
    # Header row #8 - Report_Attributes
552
    is( $report_header[7][0], 'Report_Attributes', '8th row is report attributes' );
553
    is( $report_header[7][1], '',                  '8th row is report attributes' );
554
    is( $report_header[7][2], undef,               '8th row is report attributes' );
555
556
    # Header row #9 - Exceptions
557
    is( $report_header[8][0], 'Exceptions', '9th row is exceptions' );
558
    is( $report_header[8][1], '',           '9th row is exceptions' );
559
    is( $report_header[8][2], undef,        '9th row is exceptions' );
560
561
    # Header row #10 - Reporting_Period
562
    is( $report_header[9][0], 'Reporting_Period',                           '10th row is reporting period' );
563
    is( $report_header[9][1], 'Begin_Date=2022-01-01; End_Date=2022-03-31', '10th row is reporting period' );
564
    is( $report_header[9][2], undef,                                        '10th row is reporting period' );
565
566
    # Header row #11 - Created
567
    is( $report_header[10][0], 'Created',              '11th row is created' );
568
    is( $report_header[10][1], '2023-02-15T09:11:12Z', '11th row is created' );
569
    is( $report_header[10][2], undef,                  '11th row is created' );
570
571
    # Header row #12 - Created
572
    is( $report_header[11][0], 'Created_By',       '12th row is created by' );
573
    is( $report_header[11][1], 'Sample Publisher', '12th row is created by' );
574
    is( $report_header[11][2], undef,              '12th row is created by' );
575
576
    # Header row #13 - Registry_Record
577
    is( $report_header[12][0], 'Registry_Record', '13th row is Registry_Record' );
578
579
    # Header row #14 - This needs to be empty
580
    is( $report_header[13][0], '', '14th row is empty' );
581
};
582
583
subtest 'TR_J4 _COUNTER_report_column_headings' => sub {
584
585
    plan tests => 16;
586
587
    my @report_column_headings = $sushi_counter_TR_J4->_COUNTER_report_column_headings;
588
589
    # Standard TR_J4 column headings
590
    is( $report_column_headings[0][0],  'Title',                  '1st column heading is title' );
591
    is( $report_column_headings[0][1],  'Publisher',              '2nd column heading is publisher' );
592
    is( $report_column_headings[0][2],  'Publisher_ID',           '3rd column heading is publisher ID' );
593
    is( $report_column_headings[0][3],  'Platform',               '4th column heading is platform' );
594
    is( $report_column_headings[0][4],  'DOI',                    '5th column heading is DOI' );
595
    is( $report_column_headings[0][5],  'Proprietary_ID',         '6th column heading is proprietary ID' );
596
    is( $report_column_headings[0][6],  'Print_ISSN',             '7th column heading is print ISSN' );
597
    is( $report_column_headings[0][7],  'Online_ISSN',            '8th column heading is online ISSN' );
598
    is( $report_column_headings[0][8],  'URI',                    '9th column heading is URI' );
599
    is( $report_column_headings[0][9],  'YOP',                    '10th column heading is yop' );
600
    is( $report_column_headings[0][10], 'Metric_Type',            '11th column heading is metric type' );
601
    is( $report_column_headings[0][11], 'Reporting_Period_Total', '12th column heading is reporting period total' );
602
603
    # Months column headings
604
    is( $report_column_headings[0][12], 'Jan 2022', '13th column is month column heading' );
605
    is( $report_column_headings[0][13], 'Feb 2022', '14th column is another month column heading' );
606
    is( $report_column_headings[0][14], 'Mar 2022', '15th column is the last month column heading' );
607
    is( $report_column_headings[0][15], undef,      '16th column is empty, no more months' );
608
};
609
610
subtest 'TR_J4 _COUNTER_report_body' => sub {
611
612
    plan tests => 25;
613
614
    my @report_body = $sushi_counter_TR_J4->_COUNTER_report_body;
615
616
    # The same title is sequential but for different metric types
617
    is( $report_body[0][0],  'Title 3',              'same title, different metric type' );
618
    is( $report_body[1][0],  'Title 3',              'same title, different metric type' );
619
    is( $report_body[2][0],  'Title 3',              'same title, different metric type' );
620
    is( $report_body[3][0],  'Title 3',              'same title, different metric type' );
621
    is( $report_body[0][10], 'Total_Item_Requests',  '1st title, same yop' );
622
    is( $report_body[1][10], 'Unique_Item_Requests', '1st title, same yop' );
623
    is( $report_body[2][10], 'Total_Item_Requests',  '1st title, same yop' );
624
    is( $report_body[3][10], 'Unique_Item_Requests', '1st title, same yop' );
625
    is( $report_body[0][9],  '2022',                 '1st title, yop' );
626
    is( $report_body[1][9],  '2022',                 '1st title, yop' );
627
    is( $report_body[2][9],  '2021',                 '1st title, yop' );
628
    is( $report_body[3][9],  '2021',                 '1st title, yop' );
629
630
    # The data is in the correct column
631
    is( $report_body[2][0],  'Title 3',             '1st column is title' );
632
    is( $report_body[2][1],  'Sample Publisher',    '2nd column is publisher' );
633
    is( $report_body[2][2],  '4321432143214321',    '3rd column is publisher ID' );
634
    is( $report_body[2][3],  'Platform 1',          '4th column is platform' );
635
    is( $report_body[2][4],  '10.9999/xxxxt03',     '5th column is DOI' );
636
    is( $report_body[2][5],  'P1:T03',              '6th column is proprietary ID' );
637
    is( $report_body[2][6],  '',                    '7th column is print ISSN' );
638
    is( $report_body[2][7],  '1234-4321',           '8th column is online ISSN' );
639
    is( $report_body[2][8],  '',                    '9th column is URI' );
640
    is( $report_body[2][9],  '2021',                '10th column is yop' );
641
    is( $report_body[2][10], 'Total_Item_Requests', '10th column is metric type' );
642
    is( $report_body[2][11], 640,                   '11th column is reporting period total' );    #150+247+243
643
644
    # The period total is the sum of all the month columns
645
    my $stats_total = 0;
646
    for ( my $i = 12 ; $i < 15 ; $i++ ) {
647
        $stats_total += $report_body[0][$i];
648
    }
649
    is(
650
        $report_body[0][11], $stats_total,
651
        'Reporting period total matches the sum of all the monthly usage statistics'
652
    );
653
};
654
655
my $sushi_response_file_TR_B3       = dirname(__FILE__) . $test_data_base_dir . "/TR_B3.json";
656
my $sushi_counter_51_response_TR_B3 = decode_json( read_file($sushi_response_file_TR_B3) );
657
my $sushi_counter_TR_B3 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_51_response_TR_B3 } );
658
659
subtest 'TR_B3 _COUNTER_report_header' => sub {
660
661
    plan tests => 47;
662
663
    my @report_header = $sushi_counter_TR_B3->_COUNTER_report_header;
664
665
    # Header row #1 - Report_Name
666
    is( $report_header[0][0], 'Report_Name',               '1st row is report name' );
667
    is( $report_header[0][1], 'Book Usage by Access Type', '1st row is report name' );
668
    is( $report_header[0][2], undef,                       '1st row is report name' );
669
670
    # Header row #2 - Report_ID
671
    is( $report_header[1][0], 'Report_ID', '2nd row is report name' );
672
    is( $report_header[1][1], 'TR_B3',     '2nd row is report name' );
673
    is( $report_header[1][2], undef,       '2nd row is report name' );
674
675
    # Header row #3 - Release
676
    is( $report_header[2][0], 'Release', '3rd row is counter release' );
677
    is( $report_header[2][1], '5.1',     '3rd row is counter release' );
678
    is( $report_header[2][2], undef,     '3rd row is counter release' );
679
680
    # Header row #4 - Institution_Name
681
    is( $report_header[3][0], 'Institution_Name',   '4th row is institution name' );
682
    is( $report_header[3][1], 'Sample Institution', '4th row is institution name' );
683
    is( $report_header[3][2], undef,                '4th row is institution name' );
684
685
    # Header row #5 - Institution_ID
686
    is( $report_header[4][0], 'Institution_ID',        '5th row is institution id' );
687
    is( $report_header[4][1], 'ISNI:1234123412341234', '5th row is institution id' );
688
    is( $report_header[4][2], undef,                   '5th row is institution id' );
689
690
    # Header row #6 - Metric_Types
691
    is( $report_header[5][0], 'Metric_Types', '6th row is metric types' );
692
    like( $report_header[5][1], qr/Total_Item_Investigations/,   '6th row is metric types' );
693
    like( $report_header[5][1], qr/Total_Item_Requests/,         '6th row is metric types' );
694
    like( $report_header[5][1], qr/Unique_Item_Investigations/,  '6th row is metric types' );
695
    like( $report_header[5][1], qr/Unique_Item_Requests/,        '6th row is metric types' );
696
    like( $report_header[5][1], qr/Unique_Title_Investigations/, '6th row is metric types' );
697
    like( $report_header[5][1], qr/Unique_Title_Requests/,       '6th row is metric types' );
698
699
    is( $report_header[5][2], undef, '6th row is metric types' );
700
701
    # Header row #7 - Report_Filters
702
    is( $report_header[6][0], 'Report_Filters', '7th row is report filters' );
703
    like( $report_header[6][1], qr/Data_Type:Book/,        '7th row is report filters' );
704
    like( $report_header[6][1], qr/Access_Method:Regular/, '7th row is report filters' );
705
    like(
706
        $report_header[6][1],
707
        qr/Metric_Type:Total_Item_Investigations\|Total_Item_Requests\|Unique_Item_Investigations\|Unique_Item_Requests\|Unique_Title_Investigations\|Unique_Title_Requests/,
708
        '7th row is report filters'
709
    );
710
    like( $report_header[6][1], qr/Begin_Date:2022-01-01/, '7th row is report filters' );
711
    like( $report_header[6][1], qr/End_Date:2022-03-31/,   '7th row is report filters' );
712
713
    is( $report_header[6][2], undef, '7th row is report filters' );
714
715
    # Header row #8 - Report_Attributes
716
    is( $report_header[7][0], 'Report_Attributes', '8th row is report attributes' );
717
    is( $report_header[7][1], '',                  '8th row is report attributes' );
718
    is( $report_header[7][2], undef,               '8th row is report attributes' );
719
720
    # Header row #9 - Exceptions
721
    is( $report_header[8][0], 'Exceptions', '9th row is exceptions' );
722
    is( $report_header[8][1], '',           '9th row is exceptions' );
723
    is( $report_header[8][2], undef,        '9th row is exceptions' );
724
725
    # Header row #10 - Reporting_Period
726
    is( $report_header[9][0], 'Reporting_Period',                           '10th row is reporting period' );
727
    is( $report_header[9][1], 'Begin_Date=2022-01-01; End_Date=2022-03-31', '10th row is reporting period' );
728
    is( $report_header[9][2], undef,                                        '10th row is reporting period' );
729
730
    # Header row #11 - Created
731
    is( $report_header[10][0], 'Created',              '11th row is created' );
732
    is( $report_header[10][1], '2023-02-15T09:11:12Z', '11th row is created' );
733
    is( $report_header[10][2], undef,                  '11th row is created' );
734
735
    # Header row #12 - Created
736
    is( $report_header[11][0], 'Created_By',       '12th row is created by' );
737
    is( $report_header[11][1], 'Sample Publisher', '12th row is created by' );
738
    is( $report_header[11][2], undef,              '12th row is created by' );
739
740
    # Header row #13 - Registry_Record
741
    is( $report_header[12][0], 'Registry_Record', '13th row is Registry_Record' );
742
743
    # Header row #14 - This needs to be empty
744
    is( $report_header[13][0], '', '14th row is empty' );
745
};
746
747
subtest 'TR_B3 _COUNTER_report_column_headings' => sub {
748
749
    plan tests => 19;
750
751
    my @report_column_headings = $sushi_counter_TR_B3->_COUNTER_report_column_headings;
752
753
    # Standard TR_J4 column headings
754
    is( $report_column_headings[0][0],  'Title',                  '1st column heading is title' );
755
    is( $report_column_headings[0][1],  'Publisher',              '2nd column heading is publisher' );
756
    is( $report_column_headings[0][2],  'Publisher_ID',           '3rd column heading is publisher ID' );
757
    is( $report_column_headings[0][3],  'Platform',               '4th column heading is platform' );
758
    is( $report_column_headings[0][4],  'DOI',                    '5th column heading is DOI' );
759
    is( $report_column_headings[0][5],  'Proprietary_ID',         '6th column heading is proprietary ID' );
760
    is( $report_column_headings[0][6],  'ISBN',                   '7th column heading is ISBN' );
761
    is( $report_column_headings[0][7],  'Print_ISSN',             '8th column heading is print ISSN' );
762
    is( $report_column_headings[0][8],  'Online_ISSN',            '9th column heading is online ISSN' );
763
    is( $report_column_headings[0][9],  'URI',                    '10th column heading is URI' );
764
    is( $report_column_headings[0][10], 'Data_Type',              '11th column heading is data type' );
765
    is( $report_column_headings[0][11], 'YOP',                    '12th column heading is yop' );
766
    is( $report_column_headings[0][12], 'Access_Type',            '13th column heading is access type' );
767
    is( $report_column_headings[0][13], 'Metric_Type',            '14th column heading is metric type' );
768
    is( $report_column_headings[0][14], 'Reporting_Period_Total', '15th column heading is reporting period total' );
769
770
    # Months column headings
771
    is( $report_column_headings[0][15], 'Jan 2022', '16th column is month column heading' );
772
    is( $report_column_headings[0][16], 'Feb 2022', '17th column another month column heading' );
773
    is( $report_column_headings[0][17], 'Mar 2022', '18th column is the last month column heading' );
774
    is( $report_column_headings[0][18], undef,      '19th column is empty, no more months' );
775
};
776
777
subtest 'TR_B3 _COUNTER_report_body' => sub {
778
779
    plan tests => 49;
780
781
    my @report_body = $sushi_counter_TR_B3->_COUNTER_report_body;
782
783
    # The same title is sequential but for different metric types
784
    is(
785
        $report_body[0][0], 'Title 1',
786
        'first title, different metric type'
787
    );
788
    is(
789
        $report_body[1][0], 'Title 1',
790
        'first title, different metric type'
791
    );
792
    is(
793
        $report_body[2][0], 'Title 1',
794
        'first title, different metric type'
795
    );
796
    is(
797
        $report_body[3][0], 'Title 1',
798
        'first title, different metric type'
799
    );
800
    is(
801
        $report_body[4][0], 'Title 1',
802
        'first title, different metric type'
803
    );
804
    is(
805
        $report_body[5][0], 'Title 1',
806
        'first title, different metric type'
807
    );
808
    is(
809
        $report_body[6][0], 'Title 7',
810
        'second title, different metric type'
811
    );
812
    is(
813
        $report_body[7][0], 'Title 7',
814
        'second title, different metric type'
815
    );
816
    is(
817
        $report_body[8][0], 'Title 7',
818
        'second title, different metric type'
819
    );
820
    is( $report_body[0][10], 'Book',                        '6 rows for 1st title' );
821
    is( $report_body[1][10], 'Book',                        '6 rows for 1st title' );
822
    is( $report_body[2][10], 'Book',                        '6 rows for 1st title' );
823
    is( $report_body[3][10], 'Book',                        '6 rows for 1st title' );
824
    is( $report_body[4][10], 'Book',                        '6 rows for 1st title' );
825
    is( $report_body[5][10], 'Book',                        '6 rows for 1st title' );
826
    is( $report_body[0][11], '2022',                        '1st title, yop' );
827
    is( $report_body[1][11], '2022',                        '1st title, yop' );
828
    is( $report_body[2][11], '2022',                        '1st title,yop' );
829
    is( $report_body[3][11], '2022',                        '1st title, 2nd yop has 6 metric types' );
830
    is( $report_body[4][11], '2022',                        '1st title, 2nd yop has 6 metric types' );
831
    is( $report_body[5][11], '2022',                        '1st title, 2nd yop has 6 metric types' );
832
    is( $report_body[0][12], 'Controlled',                  '6 rows for 1st title' );
833
    is( $report_body[1][12], 'Controlled',                  '6 rows for 1st title' );
834
    is( $report_body[2][12], 'Controlled',                  '6 rows for 1st title' );
835
    is( $report_body[3][12], 'Controlled',                  '6 rows for 1st title' );
836
    is( $report_body[4][12], 'Controlled',                  '6 rows for 1st title' );
837
    is( $report_body[5][12], 'Controlled',                  '6 rows for 1st title' );
838
    is( $report_body[0][13], 'Total_Item_Investigations',   '1st title, metric type' );
839
    is( $report_body[1][13], 'Total_Item_Requests',         '1st title, metric type' );
840
    is( $report_body[2][13], 'Unique_Item_Investigations',  '1st title, metric type' );
841
    is( $report_body[3][13], 'Unique_Item_Requests',        '1st title, metric type' );
842
    is( $report_body[4][13], 'Unique_Title_Investigations', '1st title, metric type' );
843
    is( $report_body[5][13], 'Unique_Title_Requests',       '1st title, metric type' );
844
845
    # The data is in the correct column
846
    is( $report_body[2][0],  'Title 1',                    '1st column is title' );
847
    is( $report_body[2][1],  'Sample Publisher',           '2nd column is publisher' );
848
    is( $report_body[2][2],  '4321432143214321',           '3rd column is publisher ID' );
849
    is( $report_body[2][3],  'Platform 1',                 '4th column is platform' );
850
    is( $report_body[2][4],  '10.9999/xxxxt01',            '5th column is DOI' );
851
    is( $report_body[2][5],  'P1:T01',                     '6th column is proprietary ID' );
852
    is( $report_body[2][6],  '979-8-88888-888-8',          '7th column is ISBN' );
853
    is( $report_body[2][7],  '',                           '8th column is print ISSN' );
854
    is( $report_body[2][8],  '',                           '9th column is online ISSN' );
855
    is( $report_body[2][9],  '',                           '10th column is URI' );
856
    is( $report_body[2][10], 'Book',                       '11th column is data_type' );
857
    is( $report_body[2][11], '2022',                       '12th column is yop' );
858
    is( $report_body[2][12], 'Controlled',                 '12th column is access type' );
859
    is( $report_body[2][13], 'Unique_Item_Investigations', '13th column is metric type' );
860
    is( $report_body[2][14], 2760,                         '14th column is reporting period total' );    #828+935+997
861
862
    # The period total is the sum of all the month columns
863
    my $stats_total = 0;
864
    for ( my $i = 15 ; $i < 18 ; $i++ ) {
865
        $stats_total += $report_body[0][$i];
866
    }
867
    is(
868
        $report_body[0][14], $stats_total,
869
        'Reporting period total matches the sum of all the monthly usage statistics'
870
    );
871
};
872
873
my $sushi_response_file_TR_B2       = dirname(__FILE__) . $test_data_base_dir . "/TR_B2.json";
874
my $sushi_counter_51_response_TR_B2 = decode_json( read_file($sushi_response_file_TR_B2) );
875
my $sushi_counter_TR_B2 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_51_response_TR_B2 } );
876
877
subtest 'TR_B2 _COUNTER_report_header' => sub {
878
879
    plan tests => 42;
880
881
    my @report_header = $sushi_counter_TR_B2->_COUNTER_report_header;
882
883
    # Header row #1 - Report_Name
884
    is( $report_header[0][0], 'Report_Name',        '1st row is report name' );
885
    is( $report_header[0][1], 'Book Access Denied', '1st row is report name' );
886
    is( $report_header[0][2], undef,                '1st row is report name' );
887
888
    # Header row #2 - Report_ID
889
    is( $report_header[1][0], 'Report_ID', '2nd row is report name' );
890
    is( $report_header[1][1], 'TR_B2',     '2nd row is report name' );
891
    is( $report_header[1][2], undef,       '2nd row is report name' );
892
893
    # Header row #3 - Release
894
    is( $report_header[2][0], 'Release', '3rd row is counter release' );
895
    is( $report_header[2][1], '5.1',     '3rd row is counter release' );
896
    is( $report_header[2][2], undef,     '3rd row is counter release' );
897
898
    # Header row #4 - Institution_Name
899
    is( $report_header[3][0], 'Institution_Name',   '4th row is institution name' );
900
    is( $report_header[3][1], 'Sample Institution', '4th row is institution name' );
901
    is( $report_header[3][2], undef,                '4th row is institution name' );
902
903
    # Header row #5 - Institution_ID
904
    is( $report_header[4][0], 'Institution_ID',        '5th row is institution id' );
905
    is( $report_header[4][1], 'ISNI:1234123412341234', '5th row is institution id' );
906
    is( $report_header[4][2], undef,                   '5th row is institution id' );
907
908
    # Header row #6 - Metric_Types
909
    is( $report_header[5][0], 'Metric_Types', '6th row is metric types' );
910
    is(
911
        $report_header[5][1],
912
        'Limit_Exceeded; No_License',
913
        '6th row is metric types'
914
    );
915
    is( $report_header[5][2], undef, '6th row is metric types' );
916
917
    # Header row #7 - Report_Filters
918
    is( $report_header[6][0], 'Report_Filters', '7th row is report filters' );
919
    like( $report_header[6][1], qr/Data_Type:Book/,                         '7th row is report filters' );
920
    like( $report_header[6][1], qr/Access_Method:Regular/,                  '7th row is report filters' );
921
    like( $report_header[6][1], qr/Metric_Type:Limit_Exceeded\|No_License/, '7th row is report filters' );
922
    like( $report_header[6][1], qr/Begin_Date:2022-01-01/,                  '7th row is report filters' );
923
    like( $report_header[6][1], qr/End_Date:2022-03-31/,                    '7th row is report filters' );
924
925
    is( $report_header[6][2], undef, '7th row is report filters' );
926
927
    # Header row #8 - Report_Attributes
928
    is( $report_header[7][0], 'Report_Attributes', '8th row is report attributes' );
929
    is( $report_header[7][1], '',                  '8th row is report attributes' );
930
    is( $report_header[7][2], undef,               '8th row is report attributes' );
931
932
    # Header row #9 - Exceptions
933
    is( $report_header[8][0], 'Exceptions', '9th row is exceptions' );
934
    is( $report_header[8][1], '',           '9th row is exceptions' );
935
    is( $report_header[8][2], undef,        '9th row is exceptions' );
936
937
    # Header row #10 - Reporting_Period
938
    is( $report_header[9][0], 'Reporting_Period',                           '10th row is reporting period' );
939
    is( $report_header[9][1], 'Begin_Date=2022-01-01; End_Date=2022-03-31', '10th row is reporting period' );
940
    is( $report_header[9][2], undef,                                        '10th row is reporting period' );
941
942
    # Header row #11 - Created
943
    is( $report_header[10][0], 'Created',              '11th row is created' );
944
    is( $report_header[10][1], '2023-02-15T09:11:12Z', '11th row is created' );
945
    is( $report_header[10][2], undef,                  '11th row is created' );
946
947
    # Header row #12 - Created
948
    is( $report_header[11][0], 'Created_By',       '12th row is created by' );
949
    is( $report_header[11][1], 'Sample Publisher', '12th row is created by' );
950
    is( $report_header[11][2], undef,              '12th row is created by' );
951
952
    # Header row #13 - Registry_Record
953
    is( $report_header[12][0], 'Registry_Record', '13th row is Registry_Record' );
954
955
    # Header row #14 - This needs to be empty
956
    is( $report_header[13][0], '', '14th row is empty' );
957
};
958
959
subtest 'TR_B2 _COUNTER_report_column_headings' => sub {
960
961
    plan tests => 18;
962
963
    my @report_column_headings = $sushi_counter_TR_B2->_COUNTER_report_column_headings;
964
965
    # Standard TR_J4 column headings
966
    is( $report_column_headings[0][0],  'Title',                  '1st column heading is title' );
967
    is( $report_column_headings[0][1],  'Publisher',              '2nd column heading is publisher' );
968
    is( $report_column_headings[0][2],  'Publisher_ID',           '3rd column heading is publisher ID' );
969
    is( $report_column_headings[0][3],  'Platform',               '4th column heading is platform' );
970
    is( $report_column_headings[0][4],  'DOI',                    '5th column heading is DOI' );
971
    is( $report_column_headings[0][5],  'Proprietary_ID',         '6th column heading is proprietary ID' );
972
    is( $report_column_headings[0][6],  'ISBN',                   '7th column heading is ISBN' );
973
    is( $report_column_headings[0][7],  'Print_ISSN',             '8th column heading is print ISSN' );
974
    is( $report_column_headings[0][8],  'Online_ISSN',            '9th column heading is online ISSN' );
975
    is( $report_column_headings[0][9],  'URI',                    '10th column heading is URI' );
976
    is( $report_column_headings[0][10], 'Data_Type',              '11th column heading is data type' );
977
    is( $report_column_headings[0][11], 'YOP',                    '12th column heading is yop' );
978
    is( $report_column_headings[0][12], 'Metric_Type',            '13th column heading is metric type' );
979
    is( $report_column_headings[0][13], 'Reporting_Period_Total', '14th column heading is reporting period total' );
980
981
    # Months column headings
982
    is( $report_column_headings[0][14], 'Jan 2022', '14th column is month column heading' );
983
    is( $report_column_headings[0][15], 'Feb 2022', '15th column is another column heading' );
984
    is( $report_column_headings[0][16], 'Mar 2022', '16th column is the last month column heading' );
985
    is( $report_column_headings[0][17], undef,      '17th column is empty, no more months' );
986
};
987
988
subtest 'TR_B2 _COUNTER_report_body' => sub {
989
990
    plan tests => 19;
991
992
    my @report_body = $sushi_counter_TR_B2->_COUNTER_report_body;
993
994
    # The same title is sequential but for different metric types
995
    is(
996
        $report_body[0][0], 'Title 1',
997
        'same title, different metric type'
998
    );
999
    is(
1000
        $report_body[1][0], 'Title 1',
1001
        'same title, different metric type'
1002
    );
1003
    is( $report_body[0][12], 'Limit_Exceeded', '2 rows for 1st title, metric type' );
1004
    is( $report_body[1][12], 'No_License',     '2 rows for 1st title, metric type' );
1005
1006
    # The data is in the correct column
1007
    is( $report_body[2][0],  'Title 7',           '1st column is title' );
1008
    is( $report_body[2][1],  'Sample Publisher',  '2nd column is publisher' );
1009
    is( $report_body[2][2],  '4321432143214321',  '3rd column heading is publisher ID' );
1010
    is( $report_body[2][3],  'Platform 1',        '4th column is platform' );
1011
    is( $report_body[2][4],  '10.9999/xxxxt07',   '5th column is DOI' );
1012
    is( $report_body[2][5],  'P1:T07',            '6th column is proprietary ID' );
1013
    is( $report_body[2][6],  '979-8-88888-888-9', '7th column is ISBN' );
1014
    is( $report_body[2][7],  '',                  '8th column is print ISSN' );
1015
    is( $report_body[2][8],  '',                  '9th column is online ISSN' );
1016
    is( $report_body[2][9],  '',                  '10th column is URI' );
1017
    is( $report_body[2][10], 'Reference_Work',    '11th column is data type' );
1018
    is( $report_body[2][11], '2019',              '11th column is yop' );
1019
    is( $report_body[2][12], 'Limit_Exceeded',    '12th column is access type' );
1020
    is( $report_body[2][13], 217,                 '13th column is reporting period total' );    #84+84+49
1021
1022
    # The period total is the sum of all the month columns
1023
    my $stats_total = 0;
1024
    for ( my $i = 14 ; $i < 17 ; $i++ ) {
1025
        $stats_total += $report_body[0][$i];
1026
    }
1027
    is(
1028
        $report_body[0][13], $stats_total,
1029
        'Reporting period total matches the sum of all the monthly usage statistics'
1030
    );
1031
};
(-)a/t/db_dependent/Koha/ERM/EUsage/CounterFile.t (-1 / +1 lines)
Lines 35-41 my $builder = t::lib::TestBuilder->new; Link Here
35
35
36
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
36
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
37
37
38
my $sushi_response_file_TR_J1      = dirname(__FILE__) . "/../../../data/erm/eusage/TR_J1.json";
38
my $sushi_response_file_TR_J1      = dirname(__FILE__) . "/../../../../data/erm/eusage/COUNTER_5/TR_J1.json";
39
my $sushi_counter_5_response_TR_J1 = read_file($sushi_response_file_TR_J1);
39
my $sushi_counter_5_response_TR_J1 = read_file($sushi_response_file_TR_J1);
40
my $sushi_counter_report_TR_J1 =
40
my $sushi_counter_report_TR_J1 =
41
    Koha::ERM::EUsage::SushiCounter->new( { response => decode_json($sushi_counter_5_response_TR_J1) } );
41
    Koha::ERM::EUsage::SushiCounter->new( { response => decode_json($sushi_counter_5_response_TR_J1) } );
(-)a/t/db_dependent/Koha/ERM/EUsage/SushiCounter.t (-6 / +7 lines)
Lines 30-36 use t::lib::TestBuilder; Link Here
30
my $schema  = Koha::Database->new->schema;
30
my $schema  = Koha::Database->new->schema;
31
my $builder = t::lib::TestBuilder->new;
31
my $builder = t::lib::TestBuilder->new;
32
32
33
my $sushi_response_file_TR_J1      = dirname(__FILE__) . "/../../../data/erm/eusage/TR_J1.json";
33
my $test_data_base_dir             = "/../../../../data/erm/eusage/COUNTER_5";
34
my $sushi_response_file_TR_J1      = dirname(__FILE__) . $test_data_base_dir . "/TR_J1.json";
34
my $sushi_counter_5_response_TR_J1 = decode_json( read_file($sushi_response_file_TR_J1) );
35
my $sushi_counter_5_response_TR_J1 = decode_json( read_file($sushi_response_file_TR_J1) );
35
my $sushi_counter_TR_J1 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J1 } );
36
my $sushi_counter_TR_J1 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J1 } );
36
37
Lines 176-182 subtest 'TR_J1 _COUNTER_report_body' => sub { Link Here
176
    );
177
    );
177
};
178
};
178
179
179
my $sushi_response_file_TR_J2      = dirname(__FILE__) . "/../../../data/erm/eusage/TR_J2.json";
180
my $sushi_response_file_TR_J2      = dirname(__FILE__) . $test_data_base_dir . "/TR_J2.json";
180
my $sushi_counter_5_response_TR_J2 = decode_json( read_file($sushi_response_file_TR_J2) );
181
my $sushi_counter_5_response_TR_J2 = decode_json( read_file($sushi_response_file_TR_J2) );
181
my $sushi_counter_TR_J2 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J2 } );
182
my $sushi_counter_TR_J2 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J2 } );
182
183
Lines 315-321 subtest 'TR_J2 _COUNTER_report_body' => sub { Link Here
315
    );
316
    );
316
};
317
};
317
318
318
my $sushi_response_file_TR_J3      = dirname(__FILE__) . "/../../../data/erm/eusage/TR_J3.json";
319
my $sushi_response_file_TR_J3      = dirname(__FILE__) . $test_data_base_dir . "/TR_J3.json";
319
my $sushi_counter_5_response_TR_J3 = decode_json( read_file($sushi_response_file_TR_J3) );
320
my $sushi_counter_5_response_TR_J3 = decode_json( read_file($sushi_response_file_TR_J3) );
320
my $sushi_counter_TR_J3 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J3 } );
321
my $sushi_counter_TR_J3 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J3 } );
321
322
Lines 468-474 subtest 'TR_J3 _COUNTER_report_body' => sub { Link Here
468
    );
469
    );
469
};
470
};
470
471
471
my $sushi_response_file_TR_J4      = dirname(__FILE__) . "/../../../data/erm/eusage/TR_J4.json";
472
my $sushi_response_file_TR_J4      = dirname(__FILE__) . $test_data_base_dir . "/TR_J4.json";
472
my $sushi_counter_5_response_TR_J4 = decode_json( read_file($sushi_response_file_TR_J4) );
473
my $sushi_counter_5_response_TR_J4 = decode_json( read_file($sushi_response_file_TR_J4) );
473
my $sushi_counter_TR_J4 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J4 } );
474
my $sushi_counter_TR_J4 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J4 } );
474
475
Lines 621-627 subtest 'TR_J4 _COUNTER_report_body' => sub { Link Here
621
    );
622
    );
622
};
623
};
623
624
624
my $sushi_response_file_TR_B3      = dirname(__FILE__) . "/../../../data/erm/eusage/TR_B3.json";
625
my $sushi_response_file_TR_B3      = dirname(__FILE__) . $test_data_base_dir . "/TR_B3.json";
625
my $sushi_counter_5_response_TR_B3 = decode_json( read_file($sushi_response_file_TR_B3) );
626
my $sushi_counter_5_response_TR_B3 = decode_json( read_file($sushi_response_file_TR_B3) );
626
my $sushi_counter_TR_B3 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_B3 } );
627
my $sushi_counter_TR_B3 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_B3 } );
627
628
Lines 829-835 subtest 'TR_B3 _COUNTER_report_body' => sub { Link Here
829
    );
830
    );
830
};
831
};
831
832
832
my $sushi_response_file_TR_B2      = dirname(__FILE__) . "/../../../data/erm/eusage/TR_B2.json";
833
my $sushi_response_file_TR_B2      = dirname(__FILE__) . $test_data_base_dir . "/TR_B2.json";
833
my $sushi_counter_5_response_TR_B2 = decode_json( read_file($sushi_response_file_TR_B2) );
834
my $sushi_counter_5_response_TR_B2 = decode_json( read_file($sushi_response_file_TR_B2) );
834
my $sushi_counter_TR_B2 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_B2 } );
835
my $sushi_counter_TR_B2 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_B2 } );
835
836
(-)a/t/db_dependent/Koha/ERM/EUsage/UsageDataProvider.t (-5 / +38 lines)
Lines 31-37 my $builder = t::lib::TestBuilder->new; Link Here
31
31
32
subtest '_build_url_query' => sub {
32
subtest '_build_url_query' => sub {
33
33
34
    plan tests => 2;
34
    plan tests => 3;
35
35
36
    $schema->storage->txn_begin;
36
    $schema->storage->txn_begin;
37
37
Lines 45-52 subtest '_build_url_query' => sub { Link Here
45
        {
45
        {
46
            class => 'Koha::ERM::EUsage::UsageDataProviders',
46
            class => 'Koha::ERM::EUsage::UsageDataProviders',
47
            value => {
47
            value => {
48
                service_url => $service_url, api_key => $api_key, requestor_id => $requestor_id,
48
                service_url => $service_url, api_key => $api_key, requestor_id     => $requestor_id,
49
                customer_id => $customer_id, name    => $name, service_platform => undef
49
                customer_id => $customer_id, name    => $name,    service_platform => undef, report_release => 5
50
            }
50
            }
51
        }
51
        }
52
    );
52
    );
Lines 78-85 subtest '_build_url_query' => sub { Link Here
78
        {
78
        {
79
            class => 'Koha::ERM::EUsage::UsageDataProviders',
79
            class => 'Koha::ERM::EUsage::UsageDataProviders',
80
            value => {
80
            value => {
81
                service_url => $service_url, api_key => $api_key, requestor_id => $requestor_id,
81
                service_url => $service_url, api_key => $api_key, requestor_id  => $requestor_id,
82
                customer_id => $customer_id, name    => $name, service_platform => $test_platform
82
                customer_id => $customer_id, name    => $name, service_platform => $test_platform, report_release => 5
83
            }
83
            }
84
        }
84
        }
85
    );
85
    );
Lines 107-112 subtest '_build_url_query' => sub { Link Here
107
            . $test_platform
107
            . $test_platform
108
    );
108
    );
109
109
110
    my $usage_data_provider_51 = $builder->build_object(
111
        {
112
            class => 'Koha::ERM::EUsage::UsageDataProviders',
113
            value => {
114
                service_url => $service_url, api_key => $api_key, requestor_id => $requestor_id,
115
                customer_id => $customer_id, name => $name, service_platform => $test_platform, report_release => '5.1'
116
            }
117
        }
118
    );
119
120
    $usage_data_provider_51->{report_type} = 'TR_J1';
121
    $usage_data_provider_51->{begin_date}  = '2023-08-01';
122
    $usage_data_provider_51->{end_date}    = '2023-09-30';
123
124
    is(
125
        $usage_data_provider_51->_build_url_query,
126
        $service_url
127
            . '/r51/reports/'
128
            . lc( $usage_data_provider->{report_type} )
129
            . '?customer_id='
130
            . $customer_id
131
            . '&requestor_id='
132
            . $requestor_id
133
            . '&api_key='
134
            . $api_key
135
            . '&begin_date='
136
            . substr( $usage_data_provider->{begin_date}, 0, 7 )
137
            . '&end_date='
138
            . substr( $usage_data_provider->{end_date}, 0, 7 )
139
            . '&platform='
140
            . $test_platform
141
    );
142
110
    $schema->storage->txn_rollback;
143
    $schema->storage->txn_rollback;
111
144
112
};
145
};
(-)a/t/db_dependent/api/v1/erm_custom_reports.t (-2 / +365 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use Test::More tests => 4;
22
use Test::More tests => 8;
23
use Test::Mojo;
23
use Test::Mojo;
24
24
25
use t::lib::TestBuilder;
25
use t::lib::TestBuilder;
Lines 40-46 my $builder = t::lib::TestBuilder->new; Link Here
40
my $t = Test::Mojo->new('Koha::REST::V1');
40
my $t = Test::Mojo->new('Koha::REST::V1');
41
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
41
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
42
42
43
my $sushi_response_file_TR_J1      = dirname(__FILE__) . "/../../data/erm/eusage/TR_J1.json";
43
my $sushi_response_file_TR_J1      = dirname(__FILE__) . "/../../data/erm/eusage/COUNTER_5/TR_J1.json";
44
my $sushi_counter_5_response_TR_J1 = decode_json( read_file($sushi_response_file_TR_J1) );
44
my $sushi_counter_5_response_TR_J1 = decode_json( read_file($sushi_response_file_TR_J1) );
45
my $report_items                   = $sushi_counter_5_response_TR_J1->{Report_Items};
45
my $report_items                   = $sushi_counter_5_response_TR_J1->{Report_Items};
46
my $sushi_counter_TR_J1 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J1 } );
46
my $sushi_counter_TR_J1 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_5_response_TR_J1 } );
Lines 403-405 subtest "provider_rollup_report" => sub { Link Here
403
403
404
    $schema->storage->txn_rollback;
404
    $schema->storage->txn_rollback;
405
};
405
};
406
407
my $sushi_response_file_51_TR_J1      = dirname(__FILE__) . "/../../data/erm/eusage/COUNTER_5.1/TR_J1.json";
408
my $sushi_counter_51_response_TR_J1 = decode_json( read_file($sushi_response_file_51_TR_J1) );
409
my $sushi_counter_51_TR_J1 = Koha::ERM::EUsage::SushiCounter->new( { response => $sushi_counter_51_response_TR_J1 } );
410
411
subtest "5.1 monthly_report" => sub {
412
    plan tests => 17;
413
414
    $schema->storage->txn_begin;
415
416
    my $librarian = $builder->build_object(
417
        {
418
            class => 'Koha::Patrons',
419
            value => { flags => 2**28 }
420
        }
421
    );
422
    my $password = 'thePassword123';
423
    $librarian->set_password( { password => $password, skip_validation => 1 } );
424
    my $userid = $librarian->userid;
425
    t::lib::Mocks::mock_userenv( { number => $userid } );
426
427
    my $patron = $builder->build_object(
428
        {
429
            class => 'Koha::Patrons',
430
            value => { flags => 0 }
431
        }
432
    );
433
434
    $patron->set_password( { password => $password, skip_validation => 1 } );
435
    my $unauth_userid = $patron->userid;
436
437
    # Run a harvest to populate the database with data
438
    my $usage_data_provider = $builder->build_object( { class => 'Koha::ERM::EUsage::UsageDataProviders' } );
439
    my $counter_file = $sushi_counter_51_TR_J1->get_COUNTER_from_SUSHI;
440
441
    $usage_data_provider->counter_files(
442
        [
443
            {
444
                usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id,
445
                file_content           => $counter_file,
446
                filename               => "Test_TR_J1",
447
            }
448
        ]
449
    );
450
451
    # Unauthorized access
452
    $t->get_ok("//$unauth_userid:$password@/api/v1/erm/eUsage/monthly_report/title")->status_is(403);
453
454
    # Authorised access
455
    my $query_string_with_no_results = 'q=[
456
        {
457
            "erm_usage_muses.year":2023,
458
            "erm_usage_muses.report_type":"TR_J1",
459
            "erm_usage_muses.month":[1,2,3,4,5,6,7,8,9,10,11,12],
460
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
461
        }
462
    ]';
463
464
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/monthly_report/title?$query_string_with_no_results" =>
465
            { 'x-koha-embed' => 'erm_usage_muses' } )->status_is(200)->json_is( [] );
466
467
    my $query_string = 'q=[
468
        {
469
            "erm_usage_muses.year":2022,
470
            "erm_usage_muses.report_type":"TR_J1",
471
            "erm_usage_muses.month":[6],
472
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
473
        }
474
    ]';
475
    my $expected_results1 = 2;    # One title, with one row for each metric type
476
477
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/monthly_report/title?$query_string" =>
478
            { 'x-koha-embed' => 'erm_usage_muses' } )->status_is(200)
479
        ->json_has( '/' . ( $expected_results1 - 2 ) . '/title_id' )
480
        ->json_has( '/' . ( $expected_results1 - 1 ) . '/title_id' )
481
        ->json_hasnt( '/' . ($expected_results1) . '/title_id' );
482
483
    my $query_string_with_multiple_years = 'q=[
484
        {
485
            "erm_usage_muses.year":2022,
486
            "erm_usage_muses.report_type":"TR_J1",
487
            "erm_usage_muses.month":[1,6,7,8],
488
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
489
        },
490
        {
491
            "erm_usage_muses.year":2021,
492
            "erm_usage_muses.report_type":"TR_J1",
493
            "erm_usage_muses.month":[1,2,3],
494
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
495
        }
496
    ]';
497
    my $expected_results2 = 4;    # Two titles this time
498
499
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/monthly_report/title?$query_string_with_multiple_years" =>
500
            { 'x-koha-embed' => 'erm_usage_muses' } )->status_is(200)
501
        ->json_has( '/' . ( $expected_results2 - 4 ) . '/title_id' )
502
        ->json_has( '/' . ( $expected_results2 - 3 ) . '/title_id' )
503
        ->json_has( '/' . ( $expected_results2 - 2 ) . '/title_id' )
504
        ->json_has( '/' . ( $expected_results2 - 1 ) . '/title_id' )
505
        ->json_hasnt( '/' . ($expected_results2) . '/title_id' );
506
507
    $schema->storage->txn_rollback;
508
};
509
510
subtest "5.1 yearly_report" => sub {
511
    plan tests => 17;
512
513
    $schema->storage->txn_begin;
514
515
    my $librarian = $builder->build_object(
516
        {
517
            class => 'Koha::Patrons',
518
            value => { flags => 2**28 }
519
        }
520
    );
521
    my $password = 'thePassword123';
522
    $librarian->set_password( { password => $password, skip_validation => 1 } );
523
    my $userid = $librarian->userid;
524
    t::lib::Mocks::mock_userenv( { number => $userid } );
525
526
    my $patron = $builder->build_object(
527
        {
528
            class => 'Koha::Patrons',
529
            value => { flags => 0 }
530
        }
531
    );
532
533
    $patron->set_password( { password => $password, skip_validation => 1 } );
534
    my $unauth_userid = $patron->userid;
535
536
    # Run a harvest to populate the database with data
537
    my $usage_data_provider = $builder->build_object( { class => 'Koha::ERM::EUsage::UsageDataProviders' } );
538
    my $counter_file = $sushi_counter_51_TR_J1->get_COUNTER_from_SUSHI;
539
540
    $usage_data_provider->counter_files(
541
        [
542
            {
543
                usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id,
544
                file_content           => $counter_file,
545
                filename               => "Test_TR_J1",
546
            }
547
        ]
548
    );
549
550
    # Unauthorized access
551
    $t->get_ok("//$unauth_userid:$password@/api/v1/erm/eUsage/yearly_report/title")->status_is(403);
552
553
    # Authorised access
554
    my $query_string_with_no_results = 'q=
555
        {
556
            "erm_usage_yuses.year":[2023],
557
            "erm_usage_yuses.report_type":"TR_J1",
558
            "erm_usage_yuses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
559
        }
560
    ';
561
562
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/yearly_report/title?$query_string_with_no_results" =>
563
            { 'x-koha-embed' => 'erm_usage_yuses' } )->status_is(200)->json_is( [] );
564
565
    my $query_string = 'q=
566
        {
567
            "erm_usage_yuses.year":[2022],
568
            "erm_usage_yuses.report_type":"TR_J1",
569
            "erm_usage_yuses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
570
        }
571
    ';
572
    my $expected_results1 = 4;    # Two titles, with one row for each metric type
573
574
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/yearly_report/title?$query_string" =>
575
            { 'x-koha-embed' => 'erm_usage_yuses' } )->status_is(200)
576
        ->json_has( '/' . ( $expected_results1 - 2 ) . '/title_id' )
577
        ->json_has( '/' . ( $expected_results1 - 1 ) . '/title_id' )
578
        ->json_hasnt( '/' . ($expected_results1) . '/title_id' );
579
580
    my $query_string_with_multiple_years = 'q=
581
        {
582
            "erm_usage_yuses.year":[2021,2022],
583
            "erm_usage_yuses.report_type":"TR_J1",
584
            "erm_usage_yuses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
585
        }
586
    ';
587
    my $expected_results2 = 4;    # Two titles this time
588
589
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/yearly_report/title?$query_string_with_multiple_years" =>
590
            { 'x-koha-embed' => 'erm_usage_yuses' } )->status_is(200)
591
        ->json_has( '/' . ( $expected_results2 - 4 ) . '/title_id' )
592
        ->json_has( '/' . ( $expected_results2 - 3 ) . '/title_id' )
593
        ->json_has( '/' . ( $expected_results2 - 2 ) . '/title_id' )
594
        ->json_has( '/' . ( $expected_results2 - 1 ) . '/title_id' )
595
        ->json_hasnt( '/' . ($expected_results2) . '/title_id' );
596
597
    $schema->storage->txn_rollback;
598
};
599
600
subtest "5.1 metric_types_report" => sub {
601
    plan tests => 14;
602
603
    $schema->storage->txn_begin;
604
605
    my $librarian = $builder->build_object(
606
        {
607
            class => 'Koha::Patrons',
608
            value => { flags => 2**28 }
609
        }
610
    );
611
    my $password = 'thePassword123';
612
    $librarian->set_password( { password => $password, skip_validation => 1 } );
613
    my $userid = $librarian->userid;
614
    t::lib::Mocks::mock_userenv( { number => $userid } );
615
616
    my $patron = $builder->build_object(
617
        {
618
            class => 'Koha::Patrons',
619
            value => { flags => 0 }
620
        }
621
    );
622
623
    $patron->set_password( { password => $password, skip_validation => 1 } );
624
    my $unauth_userid = $patron->userid;
625
626
    # Run a harvest to populate the database with data
627
    my $usage_data_provider = $builder->build_object( { class => 'Koha::ERM::EUsage::UsageDataProviders' } );
628
    my $counter_file = $sushi_counter_51_TR_J1->get_COUNTER_from_SUSHI;
629
630
    $usage_data_provider->counter_files(
631
        [
632
            {
633
                usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id,
634
                file_content           => $counter_file,
635
                filename               => "Test_TR_J1",
636
            }
637
        ]
638
    );
639
640
    # Unauthorized access
641
    $t->get_ok("//$unauth_userid:$password@/api/v1/erm/eUsage/metric_types_report/title")->status_is(403);
642
643
    # Authorised access
644
    my $query_string_with_no_results = 'q=[
645
        {
646
            "erm_usage_muses.year":2023,
647
            "erm_usage_muses.report_type":"TR_J1",
648
            "erm_usage_muses.month":[1,2,3,4,5,6,7,8,9,10,11,12],
649
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
650
        }
651
    ]';
652
653
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/metric_types_report/title?$query_string_with_no_results" =>
654
            { 'x-koha-embed' => 'erm_usage_muses' } )->status_is(200)->json_is( [] );
655
656
    my $query_string = 'q=[
657
        {
658
            "erm_usage_muses.year":2022,
659
            "erm_usage_muses.report_type":"TR_J1",
660
            "erm_usage_muses.month":[6],
661
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
662
        }
663
    ]';
664
    my $expected_results1 = 1;    # One title
665
666
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/metric_types_report/title?$query_string" =>
667
            { 'x-koha-embed' => 'erm_usage_muses' } )->status_is(200)
668
        ->json_has( '/' . ( $expected_results1 - 1 ) . '/title_id' )
669
        ->json_hasnt( '/' . ($expected_results1) . '/title_id' );
670
671
    my $query_string_with_multiple_years = 'q=[
672
        {
673
            "erm_usage_muses.year":2022,
674
            "erm_usage_muses.report_type":"TR_J1",
675
            "erm_usage_muses.month":[1,2,3,6,7,8],
676
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
677
        },
678
        {
679
            "erm_usage_muses.year":2021,
680
            "erm_usage_muses.report_type":"TR_J1",
681
            "erm_usage_muses.month":[1,2,3],
682
            "erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
683
        }
684
    ]';
685
    my $expected_results2 = 2;    # Two titles this time
686
687
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/metric_types_report/title?$query_string_with_multiple_years" =>
688
            { 'x-koha-embed' => 'erm_usage_muses' } )->status_is(200)
689
        ->json_has( '/' . ( $expected_results2 - 2 ) . '/title_id' )
690
        ->json_has( '/' . ( $expected_results2 - 1 ) . '/title_id' )
691
        ->json_hasnt( '/' . ($expected_results2) . '/title_id' );
692
693
    $schema->storage->txn_rollback;
694
};
695
696
subtest "5.1 provider_rollup_report" => sub {
697
    plan tests => 9;
698
699
    $schema->storage->txn_begin;
700
701
    my $librarian = $builder->build_object(
702
        {
703
            class => 'Koha::Patrons',
704
            value => { flags => 2**28 }
705
        }
706
    );
707
    my $password = 'thePassword123';
708
    $librarian->set_password( { password => $password, skip_validation => 1 } );
709
    my $userid = $librarian->userid;
710
    t::lib::Mocks::mock_userenv( { number => $userid } );
711
712
    my $patron = $builder->build_object(
713
        {
714
            class => 'Koha::Patrons',
715
            value => { flags => 0 }
716
        }
717
    );
718
719
    $patron->set_password( { password => $password, skip_validation => 1 } );
720
    my $unauth_userid = $patron->userid;
721
722
    # Run a harvest to populate the database with data
723
    my $usage_data_provider = $builder->build_object( { class => 'Koha::ERM::EUsage::UsageDataProviders' } );
724
    my $counter_file = $sushi_counter_51_TR_J1->get_COUNTER_from_SUSHI;
725
726
    $usage_data_provider->counter_files(
727
        [
728
            {
729
                usage_data_provider_id => $usage_data_provider->erm_usage_data_provider_id,
730
                file_content           => $counter_file,
731
                filename               => "Test_TR_J1",
732
            }
733
        ]
734
    );
735
736
    # Unauthorized access
737
    $t->get_ok("//$unauth_userid:$password@/api/v1/erm/eUsage/provider_rollup_report/title")->status_is(403);
738
739
    # Authorised access
740
    my $query_string_with_no_results = 'q=[
741
        {
742
            "erm_usage_titles.erm_usage_muses.year":2023,
743
            "erm_usage_titles.erm_usage_muses.report_type":"TR_J1",
744
            "erm_usage_titles.erm_usage_muses.month":[1,2,3,4,5,6,7,8,9,10,11,12],
745
            "erm_usage_titles.erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
746
        }
747
    ]';
748
749
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/provider_rollup_report/title?$query_string_with_no_results" =>
750
            { 'x-koha-embed' => 'erm_usage_titles.erm_usage_muses' } )->status_is(200)->json_is( [] );
751
752
    my $query_string = 'q=[
753
        {
754
            "erm_usage_titles.erm_usage_muses.year":2022,
755
            "erm_usage_titles.erm_usage_muses.report_type":"TR_J1",
756
            "erm_usage_titles.erm_usage_muses.month":[1,6],
757
            "erm_usage_titles.erm_usage_muses.metric_type":["Total_Item_Requests","Unique_Item_Requests"]
758
        }
759
    ]';
760
    my $expected_results1 = 2;    # One provider repeated once for each metric type
761
762
    $t->get_ok( "//$userid:$password@/api/v1/erm/eUsage/provider_rollup_report/title?$query_string" =>
763
            { 'x-koha-embed' => 'erm_usage_titles.erm_usage_muses' } )->status_is(200)
764
        ->json_is( '/' . ( $expected_results1 - 2 ) . '/provider_rollup_total' => 528, 'Total is correct' )
765
        ->json_is( '/' . ( $expected_results1 - 1 ) . '/provider_rollup_total' => 228, 'Total is correct' );
766
767
    $schema->storage->txn_rollback;
768
};
(-)a/t/db_dependent/data/erm/eusage/COUNTER_5.1/TR_B2.json (+101 lines)
Line 0 Link Here
1
{
2
  "Report_Header": {
3
    "Release": "5.1",
4
    "Report_ID": "TR_B2",
5
    "Report_Name": "Book Access Denied",
6
    "Created": "2023-02-15T09:11:12Z",
7
    "Created_By": "Sample Publisher",
8
    "Institution_ID": {
9
      "ISNI": [
10
        "1234123412341234"
11
      ]
12
    },
13
    "Institution_Name": "Sample Institution",
14
    "Registry_Record": "https://registry.projectcounter.org/platform/99999999-9999-9999-9999-999999999999",
15
    "Report_Filters": {
16
      "Metric_Type": [
17
        "Limit_Exceeded",
18
        "No_License"
19
      ],
20
      "Begin_Date": "2022-01-01",
21
      "End_Date": "2022-03-31",
22
      "Data_Type": [
23
        "Book",
24
        "Reference_Work"
25
      ],
26
      "Access_Method": [
27
        "Regular"
28
      ]
29
    }
30
  },
31
  "Report_Items": [
32
    {
33
      "Title": "Title 1",
34
      "Publisher": "Sample Publisher",
35
      "Publisher_ID": {
36
        "ISNI": [
37
          "4321432143214321"
38
        ]
39
      },
40
      "Platform": "Platform 1",
41
      "Item_ID": {
42
        "DOI": "10.9999/xxxxt01",
43
        "Proprietary": "P1:T01",
44
        "ISBN": "979-8-88888-888-8",
45
        "URI": "https://doi.org/10.9999/xxxxt01"
46
      },
47
      "Attribute_Performance": [
48
        {
49
          "Data_Type": "Book",
50
          "YOP": "2022",
51
          "Performance": {
52
            "Limit_Exceeded": {
53
              "2022-01": 49,
54
              "2022-02": 90,
55
              "2022-03": 40
56
            },
57
            "No_License": {
58
              "2022-01": 50,
59
              "2022-02": 84,
60
              "2022-03": 47
61
            }
62
          }
63
        }
64
      ]
65
    },
66
    {
67
      "Title": "Title 7",
68
      "Publisher": "Sample Publisher",
69
      "Publisher_ID": {
70
        "ISNI": [
71
          "4321432143214321"
72
        ]
73
      },
74
      "Platform": "Platform 1",
75
      "Item_ID": {
76
        "DOI": "10.9999/xxxxt07",
77
        "Proprietary": "P1:T07",
78
        "ISBN": "979-8-88888-888-9",
79
        "URI": "https://doi.org/10.9999/xxxxt07"
80
      },
81
      "Attribute_Performance": [
82
        {
83
          "Data_Type": "Reference_Work",
84
          "YOP": "2019",
85
          "Performance": {
86
            "Limit_Exceeded": {
87
              "2022-01": 84,
88
              "2022-02": 84,
89
              "2022-03": 49
90
            },
91
            "No_License": {
92
              "2022-01": 70,
93
              "2022-02": 74,
94
              "2022-03": 54
95
            }
96
          }
97
        }
98
      ]
99
    }
100
  ]
101
}
(-)a/t/db_dependent/data/erm/eusage/COUNTER_5.1/TR_B3.json (+147 lines)
Line 0 Link Here
1
{
2
  "Report_Header": {
3
    "Release": "5.1",
4
    "Report_ID": "TR_B3",
5
    "Report_Name": "Book Usage by Access Type",
6
    "Created": "2023-02-15T09:11:12Z",
7
    "Created_By": "Sample Publisher",
8
    "Institution_ID": {
9
      "ISNI": [
10
        "1234123412341234"
11
      ]
12
    },
13
    "Institution_Name": "Sample Institution",
14
    "Registry_Record": "https://registry.projectcounter.org/platform/99999999-9999-9999-9999-999999999999",
15
    "Report_Filters": {
16
      "Metric_Type": [
17
        "Total_Item_Investigations",
18
        "Total_Item_Requests",
19
        "Unique_Item_Investigations",
20
        "Unique_Item_Requests",
21
        "Unique_Title_Investigations",
22
        "Unique_Title_Requests"
23
      ],
24
      "Begin_Date": "2022-01-01",
25
      "End_Date": "2022-03-31",
26
      "Data_Type": [
27
        "Book",
28
        "Reference_Work"
29
      ],
30
      "Access_Method": [
31
        "Regular"
32
      ]
33
    }
34
  },
35
  "Report_Items": [
36
    {
37
      "Title": "Title 1",
38
      "Publisher": "Sample Publisher",
39
      "Publisher_ID": {
40
        "ISNI": [
41
          "4321432143214321"
42
        ]
43
      },
44
      "Platform": "Platform 1",
45
      "Item_ID": {
46
        "DOI": "10.9999/xxxxt01",
47
        "Proprietary": "P1:T01",
48
        "ISBN": "979-8-88888-888-8",
49
        "URI": "https://doi.org/10.9999/xxxxt01"
50
      },
51
      "Attribute_Performance": [
52
        {
53
          "Data_Type": "Book",
54
          "YOP": "2022",
55
          "Access_Type": "Controlled",
56
          "Performance": {
57
            "Total_Item_Investigations": {
58
              "2022-01": 1104,
59
              "2022-02": 1246,
60
              "2022-03": 1329
61
            },
62
            "Total_Item_Requests": {
63
              "2022-01": 662,
64
              "2022-02": 748,
65
              "2022-03": 797
66
            },
67
            "Unique_Item_Investigations": {
68
              "2022-01": 828,
69
              "2022-02": 935,
70
              "2022-03": 997
71
            },
72
            "Unique_Item_Requests": {
73
              "2022-01": 497,
74
              "2022-02": 561,
75
              "2022-03": 598
76
            },
77
            "Unique_Title_Investigations": {
78
              "2022-01": 552,
79
              "2022-02": 623,
80
              "2022-03": 665
81
            },
82
            "Unique_Title_Requests": {
83
              "2022-01": 414,
84
              "2022-02": 467,
85
              "2022-03": 499
86
            }
87
          }
88
        }
89
      ]
90
    },
91
    {
92
      "Title": "Title 7",
93
      "Publisher": "Sample Publisher",
94
      "Publisher_ID": {
95
        "ISNI": [
96
          "4321432143214321"
97
        ]
98
      },
99
      "Platform": "Platform 1",
100
      "Item_ID": {
101
        "DOI": "10.9999/xxxxt07",
102
        "Proprietary": "P1:T07",
103
        "ISBN": "979-8-88888-888-9",
104
        "URI": "https://doi.org/10.9999/xxxxt07"
105
      },
106
      "Attribute_Performance": [
107
        {
108
          "Data_Type": "Reference_Work",
109
          "YOP": "2019",
110
          "Access_Type": "Controlled",
111
          "Performance": {
112
            "Total_Item_Investigations": {
113
              "2022-01": 1645,
114
              "2022-02": 1022,
115
              "2022-03": 1106
116
            },
117
            "Total_Item_Requests": {
118
              "2022-01": 987,
119
              "2022-02": 613,
120
              "2022-03": 664
121
            },
122
            "Unique_Item_Investigations": {
123
              "2022-01": 1234,
124
              "2022-02": 767,
125
              "2022-03": 830
126
            },
127
            "Unique_Item_Requests": {
128
              "2022-01": 740,
129
              "2022-02": 460,
130
              "2022-03": 498
131
            },
132
            "Unique_Title_Investigations": {
133
              "2022-01": 301,
134
              "2022-02": 283,
135
              "2022-03": 217
136
            },
137
            "Unique_Title_Requests": {
138
              "2022-01": 226,
139
              "2022-02": 212,
140
              "2022-03": 163
141
            }
142
          }
143
        }
144
      ]
145
    }
146
  ]
147
}
(-)a/t/db_dependent/data/erm/eusage/COUNTER_5.1/TR_J1.json (+104 lines)
Line 0 Link Here
1
{
2
  "Report_Header": {
3
    "Release": "5.1",
4
    "Report_ID": "TR_J1",
5
    "Report_Name": "Journal Requests (Excluding OA_Gold)",
6
    "Created": "2023-08-29T07:11:41Z",
7
    "Created_By": "Test Systems Inc.",
8
    "Institution_ID": {
9
      "Proprietary": [
10
        "TInsti:EALTEST001"
11
      ],
12
      "ISNI": [
13
        "0000000123456789"
14
      ]
15
    },
16
    "Institution_Name": "Test Institution",
17
    "Registry_Record": "https://registry.projectcounter.org/platform/99999999-9999-9999-9999-999999999999",
18
    "Report_Filters": {
19
      "Metric_Type": [
20
        "Total_Item_Requests",
21
        "Unique_Item_Requests"
22
      ],
23
      "Begin_Date": "2021-09-01",
24
      "End_Date": "2022-09-30",
25
      "Data_Type": [
26
        "Journal"
27
      ],
28
      "Access_Type": [
29
        "Controlled"
30
      ],
31
      "Access_Method": [
32
        "Regular"
33
      ],
34
      "Data_Type": [
35
        "Journal"
36
      ]
37
    }
38
  },
39
  "Report_Items": [
40
    {
41
      "Title": "Education and Training",
42
      "Publisher": "Sample Publisher",
43
      "Publisher_ID": {
44
        "ISNI": [
45
          "4321432143214321"
46
        ]
47
      },
48
      "Platform": "Platform 1",
49
      "Item_ID": {
50
        "DOI": "10.9999/xxxxt03",
51
        "Proprietary": "P1:T03",
52
        "Online_ISSN": "1234-4321",
53
        "URI": "https://doi.org/10.9999/xxxxt03"
54
      },
55
      "Attribute_Performance": [
56
        {
57
          "Performance": {
58
            "Total_Item_Requests": {
59
              "2022-01": 526,
60
              "2022-02": 866,
61
              "2022-03": 852
62
            },
63
            "Unique_Item_Requests": {
64
              "2022-01": 226,
65
              "2022-02": 372,
66
              "2022-03": 366
67
            }
68
          }
69
        }
70
      ]
71
    },
72
    {
73
      "Title": "Test Journal",
74
      "Publisher": "Test Publisher",
75
      "Publisher_ID": {
76
        "ISNI": [
77
          "0000000123456789"
78
        ]
79
      },
80
      "Platform": "Unit Test Library",
81
      "Item_ID": {
82
        "DOI": "10.1002/(ISSN)1111-2222",
83
        "Proprietary": "TInsti:ABC1",
84
        "Online_ISSN": "5555-6666",
85
        "URI": "https://doi.org/10.9999/xxxxt03",
86
        "Print_ISSN": "7777-8888"
87
      },
88
      "Attribute_Performance": [
89
        {
90
          "Performance": {
91
            "Total_Item_Requests": {
92
              "2022-01": 1,
93
              "2022-06": 1
94
            },
95
            "Unique_Item_Requests": {
96
              "2022-01": 1,
97
              "2022-06": 1
98
            }
99
          }
100
        }
101
      ]
102
    }
103
  ]
104
}
(-)a/t/db_dependent/data/erm/eusage/COUNTER_5.1/TR_J2.json (+96 lines)
Line 0 Link Here
1
{
2
  "Report_Header": {
3
    "Release": "5.1",
4
    "Report_ID": "TR_J2",
5
    "Report_Name": "Journal Access Denied",
6
    "Created": "2023-02-15T09:11:12Z",
7
    "Created_By": "Sample Publisher",
8
    "Institution_ID": {
9
      "ISNI": [
10
        "1234123412341234"
11
      ]
12
    },
13
    "Institution_Name": "Sample Institution",
14
    "Registry_Record": "https://registry.projectcounter.org/platform/99999999-9999-9999-9999-999999999999",
15
    "Report_Filters": {
16
      "Metric_Type": [
17
        "Limit_Exceeded",
18
        "No_License"
19
      ],
20
      "Begin_Date": "2022-01-01",
21
      "End_Date": "2022-03-31",
22
      "Data_Type": [
23
        "Journal"
24
      ],
25
      "Access_Method": [
26
        "Regular"
27
      ]
28
    }
29
  },
30
  "Report_Items": [
31
    {
32
      "Title": "Title 3",
33
      "Publisher": "Sample Publisher",
34
      "Publisher_ID": {
35
        "ISNI": [
36
          "4321432143214321"
37
        ]
38
      },
39
      "Platform": "Platform 1",
40
      "Item_ID": {
41
        "DOI": "10.9999/xxxxt03",
42
        "Proprietary": "P1:T03",
43
        "Online_ISSN": "1234-4321",
44
        "URI": "https://doi.org/10.9999/xxxxt03"
45
      },
46
      "Attribute_Performance": [
47
        {
48
          "Performance": {
49
            "Limit_Exceeded": {
50
              "2022-01": 174,
51
              "2022-02": 176,
52
              "2022-03": 90
53
            },
54
            "No_License": {
55
              "2022-01": 96,
56
              "2022-02": 160,
57
              "2022-03": 74
58
            }
59
          }
60
        }
61
      ]
62
    },
63
    {
64
      "Title": "Another title",
65
      "Publisher": "Another publisher",
66
      "Publisher_ID": {
67
        "ISNI": [
68
          "4321432143214321"
69
        ]
70
      },
71
      "Platform": "Platform 1",
72
      "Item_ID": {
73
        "DOI": "10.9999/xxxxt03",
74
        "Proprietary": "P1:T03",
75
        "Online_ISSN": "1234-4321",
76
        "URI": "https://doi.org/10.9999/xxxxt03"
77
      },
78
      "Attribute_Performance": [
79
        {
80
          "Performance": {
81
            "Limit_Exceeded": {
82
              "2022-01": 222,
83
              "2022-02": 111,
84
              "2022-03": 55
85
            },
86
            "No_License": {
87
              "2022-01": 11,
88
              "2022-02": 22,
89
              "2022-03": 33
90
            }
91
          }
92
        }
93
      ]
94
    }
95
  ]
96
}
(-)a/t/db_dependent/data/erm/eusage/COUNTER_5.1/TR_J3.json (+170 lines)
Line 0 Link Here
1
{
2
  "Report_Header": {
3
    "Release": "5.1",
4
    "Report_ID": "TR_J3",
5
    "Report_Name": "Journal Usage by Access Type",
6
    "Created": "2023-02-15T09:11:12Z",
7
    "Created_By": "Sample Publisher",
8
    "Institution_ID": {
9
      "ISNI": [
10
        "1234123412341234"
11
      ]
12
    },
13
    "Institution_Name": "Sample Institution",
14
    "Registry_Record": "https://registry.projectcounter.org/platform/99999999-9999-9999-9999-999999999999",
15
    "Report_Filters": {
16
      "Metric_Type": [
17
        "Total_Item_Investigations",
18
        "Total_Item_Requests",
19
        "Unique_Item_Investigations",
20
        "Unique_Item_Requests"
21
      ],
22
      "Begin_Date": "2022-01-01",
23
      "End_Date": "2022-03-31",
24
      "Data_Type": [
25
        "Journal"
26
      ],
27
      "Access_Method": [
28
        "Regular"
29
      ]
30
    }
31
  },
32
  "Report_Items": [
33
    {
34
      "Title": "Title 3",
35
      "Publisher": "Sample Publisher",
36
      "Publisher_ID": {
37
        "ISNI": [
38
          "4321432143214321"
39
        ]
40
      },
41
      "Platform": "Platform 1",
42
      "Item_ID": {
43
        "DOI": "10.9999/xxxxt03",
44
        "Proprietary": "P1:T03",
45
        "Online_ISSN": "1234-4321",
46
        "URI": "https://doi.org/10.9999/xxxxt03"
47
      },
48
      "Attribute_Performance": [
49
        {
50
          "Access_Type": "Controlled",
51
          "Performance": {
52
            "Total_Item_Investigations": {
53
              "2022-01": 500,
54
              "2022-02": 824,
55
              "2022-03": 812
56
            },
57
            "Total_Item_Requests": {
58
              "2022-01": 300,
59
              "2022-02": 494,
60
              "2022-03": 486
61
            },
62
            "Unique_Item_Investigations": {
63
              "2022-01": 376,
64
              "2022-02": 618,
65
              "2022-03": 608
66
            },
67
            "Unique_Item_Requests": {
68
              "2022-01": 226,
69
              "2022-02": 372,
70
              "2022-03": 366
71
            }
72
          }
73
        },
74
        {
75
          "Access_Type": "Open",
76
          "Performance": {
77
            "Total_Item_Investigations": {
78
              "2022-01": 1504,
79
              "2022-02": 2476,
80
              "2022-03": 2434
81
            },
82
            "Total_Item_Requests": {
83
              "2022-01": 902,
84
              "2022-02": 1486,
85
              "2022-03": 1462
86
            },
87
            "Unique_Item_Investigations": {
88
              "2022-01": 1128,
89
              "2022-02": 1858,
90
              "2022-03": 1826
91
            },
92
            "Unique_Item_Requests": {
93
              "2022-01": 676,
94
              "2022-02": 1114,
95
              "2022-03": 1096
96
            }
97
          }
98
        }
99
      ]
100
    },
101
    {
102
      "Title": "Title 4",
103
      "Publisher": "Sample Publisher",
104
      "Publisher_ID": {
105
        "ISNI": [
106
          "4321432143214321"
107
        ]
108
      },
109
      "Platform": "Platform 1",
110
      "Item_ID": {
111
        "DOI": "10.9999",
112
        "Proprietary": "P1:T03",
113
        "Online_ISSN": "1234-4321",
114
        "URI": "https://doi.org/10.9999"
115
      },
116
      "Attribute_Performance": [
117
        {
118
          "Access_Type": "Controlled",
119
          "Performance": {
120
            "Total_Item_Investigations": {
121
              "2022-01": 3,
122
              "2022-02": 4,
123
              "2022-03": 9
124
            },
125
            "Total_Item_Requests": {
126
              "2022-01": 55,
127
              "2022-02": 44,
128
              "2022-03": 33
129
            },
130
            "Unique_Item_Investigations": {
131
              "2022-01": 88,
132
              "2022-02": 55,
133
              "2022-03": 77
134
            },
135
            "Unique_Item_Requests": {
136
              "2022-01": 22,
137
              "2022-02": 33,
138
              "2022-03": 44
139
            }
140
          }
141
        },
142
        {
143
          "Access_Type": "Open",
144
          "Performance": {
145
            "Total_Item_Investigations": {
146
              "2022-01": 55,
147
              "2022-02": 76,
148
              "2022-03": 12
149
            },
150
            "Total_Item_Requests": {
151
              "2022-01": 65,
152
              "2022-02": 34,
153
              "2022-03": 87
154
            },
155
            "Unique_Item_Investigations": {
156
              "2022-01": 12,
157
              "2022-02": 66,
158
              "2022-03": 88
159
            },
160
            "Unique_Item_Requests": {
161
              "2022-01": 45,
162
              "2022-02": 23,
163
              "2022-03": 76
164
            }
165
          }
166
        }
167
      ]
168
    }
169
  ]
170
}
(-)a/t/db_dependent/data/erm/eusage/COUNTER_5.1/TR_J4.json (+83 lines)
Line 0 Link Here
1
{
2
  "Report_Header": {
3
    "Release": "5.1",
4
    "Report_ID": "TR_J4",
5
    "Report_Name": "Journal Requests by YOP (Controlled)",
6
    "Created": "2023-02-15T09:11:12Z",
7
    "Created_By": "Sample Publisher",
8
    "Institution_ID": {
9
      "ISNI": [
10
        "1234123412341234"
11
      ]
12
    },
13
    "Institution_Name": "Sample Institution",
14
    "Registry_Record": "https://registry.projectcounter.org/platform/99999999-9999-9999-9999-999999999999",
15
    "Report_Filters": {
16
      "Metric_Type": [
17
        "Total_Item_Requests",
18
        "Unique_Item_Requests"
19
      ],
20
      "Begin_Date": "2022-01-01",
21
      "End_Date": "2022-03-31",
22
      "Data_Type": [
23
        "Journal"
24
      ],
25
      "Access_Type": [
26
        "Controlled"
27
      ],
28
      "Access_Method": [
29
        "Regular"
30
      ]
31
    }
32
  },
33
  "Report_Items": [
34
    {
35
      "Title": "Title 3",
36
      "Publisher": "Sample Publisher",
37
      "Publisher_ID": {
38
        "ISNI": [
39
          "4321432143214321"
40
        ]
41
      },
42
      "Platform": "Platform 1",
43
      "Item_ID": {
44
        "DOI": "10.9999/xxxxt03",
45
        "Proprietary": "P1:T03",
46
        "Online_ISSN": "1234-4321",
47
        "URI": "https://doi.org/10.9999/xxxxt03"
48
      },
49
      "Attribute_Performance": [
50
        {
51
          "YOP": "2022",
52
          "Performance": {
53
            "Total_Item_Requests": {
54
              "2022-01": 150,
55
              "2022-02": 247,
56
              "2022-03": 243
57
            },
58
            "Unique_Item_Requests": {
59
              "2022-01": 113,
60
              "2022-02": 186,
61
              "2022-03": 183
62
            }
63
          }
64
        },
65
        {
66
          "YOP": "2021",
67
          "Performance": {
68
            "Total_Item_Requests": {
69
              "2022-01": 150,
70
              "2022-02": 247,
71
              "2022-03": 243
72
            },
73
            "Unique_Item_Requests": {
74
              "2022-01": 113,
75
              "2022-02": 186,
76
              "2022-03": 183
77
            }
78
          }
79
        }
80
      ]
81
    }
82
  ]
83
}
(-)a/t/db_dependent/data/erm/eusage/UnsupportedCOUNTER/UnsupportedCOUNTER.json (-1 / +101 lines)
Line 0 Link Here
0
- 
1
{
2
  "Report_Header": {
3
    "Release": "99",
4
    "Report_ID": "TR_B2",
5
    "Report_Name": "Book Access Denied",
6
    "Created": "2023-02-15T09:11:12Z",
7
    "Created_By": "Sample Publisher",
8
    "Institution_ID": {
9
      "ISNI": [
10
        "1234123412341234"
11
      ]
12
    },
13
    "Institution_Name": "Sample Institution",
14
    "Registry_Record": "https://registry.projectcounter.org/platform/99999999-9999-9999-9999-999999999999",
15
    "Report_Filters": {
16
      "Metric_Type": [
17
        "Limit_Exceeded",
18
        "No_License"
19
      ],
20
      "Begin_Date": "2022-01-01",
21
      "End_Date": "2022-03-31",
22
      "Data_Type": [
23
        "Book",
24
        "Reference_Work"
25
      ],
26
      "Access_Method": [
27
        "Regular"
28
      ]
29
    }
30
  },
31
  "Report_Items": [
32
    {
33
      "Title": "Title 1",
34
      "Publisher": "Sample Publisher",
35
      "Publisher_ID": {
36
        "ISNI": [
37
          "4321432143214321"
38
        ]
39
      },
40
      "Platform": "Platform 1",
41
      "Item_ID": {
42
        "DOI": "10.9999/xxxxt01",
43
        "Proprietary": "P1:T01",
44
        "ISBN": "979-8-88888-888-8",
45
        "URI": "https://doi.org/10.9999/xxxxt01"
46
      },
47
      "Attribute_Performance": [
48
        {
49
          "Data_Type": "Book",
50
          "YOP": "2022",
51
          "Performance": {
52
            "Limit_Exceeded": {
53
              "2022-01": 49,
54
              "2022-02": 90,
55
              "2022-03": 40
56
            },
57
            "No_License": {
58
              "2022-01": 50,
59
              "2022-02": 84,
60
              "2022-03": 47
61
            }
62
          }
63
        }
64
      ]
65
    },
66
    {
67
      "Title": "Title 7",
68
      "Publisher": "Sample Publisher",
69
      "Publisher_ID": {
70
        "ISNI": [
71
          "4321432143214321"
72
        ]
73
      },
74
      "Platform": "Platform 1",
75
      "Item_ID": {
76
        "DOI": "10.9999/xxxxt07",
77
        "Proprietary": "P1:T07",
78
        "ISBN": "979-8-88888-888-9",
79
        "URI": "https://doi.org/10.9999/xxxxt07"
80
      },
81
      "Attribute_Performance": [
82
        {
83
          "Data_Type": "Reference_Work",
84
          "YOP": "2019",
85
          "Performance": {
86
            "Limit_Exceeded": {
87
              "2022-01": 84,
88
              "2022-02": 84,
89
              "2022-03": 49
90
            },
91
            "No_License": {
92
              "2022-01": 70,
93
              "2022-02": 74,
94
              "2022-03": 54
95
            }
96
          }
97
        }
98
      ]
99
    }
100
  ]
101
}

Return to bug 39345