Bug 34587: Add reports by data provider

Add the option to have a report by provider that rolls all usage up into one top-level figure to see how often that provider is being used a given period

Signed-off-by: Jessica Zairo <jzairo@bywatersolutions.com>
Signed-off-by: Michaela Sieber <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
Matt Blenkinsop 2023-06-16 16:27:53 +00:00 committed by Tomas Cohen Arazi
parent ffbcf83b95
commit e1583a334a
Signed by: tomascohen
GPG key ID: 0A272EA1B2F3C15F
7 changed files with 297 additions and 24 deletions

View file

@ -921,6 +921,61 @@ sub get_report_type_specific_fields {
}
=head3 test_connection
Tests the connection of the harvester to the SUSHI service and returns any alerts of planned SUSHI outages
=cut
sub test_connection {
my ($self) = @_;
my $url = $self->service_url;
$url .= '/status';
$url .= '?customer_id=' . $self->customer_id;
$url .= '&requestor_id=' . $self->requestor_id if $self->requestor_id;
$url .= '&api_key=' . $self->api_key if $self->api_key;
my $request = HTTP::Request->new( 'GET' => $url );
my $ua = LWP::UserAgent->new;
my $response = $ua->simple_request($request);
my @result = decode_json( $response->decoded_content );
if ( $result[0][0]->{Service_Active} ) {
return 1;
}
else {
return 0;
}
}
=head3 erm_usage_titles
Method to embed erm_usage_titles to titles for report formatting
=cut
sub erm_usage_titles {
my ($self) = @_;
my $usage_title_rs = $self->_result->erm_usage_titles;
return Koha::ERM::UsageTitles->_new_from_dbic($usage_title_rs);
}
=head3 erm_usage_muses
Method to embed erm_usage_muses to titles for report formatting
=cut
sub erm_usage_muses {
my ($self) = @_;
my $usage_mus_rs = $self->_result->erm_usage_muses;
return Koha::ERM::MonthlyUsages->_new_from_dbic($usage_mus_rs);
}
=head3 _type
=cut

View file

@ -359,4 +359,92 @@ sub test_connection {
};
}
=head3 providers_report
=cut
sub providers_report {
my $c = shift->openapi->valid_input or return;
return try {
my $args = $c->validation->output;
my $usage_data_providers_set = Koha::ERM::UsageDataProviders->new;
my $usage_data_providers = $c->objects->search( $usage_data_providers_set );
my @query_params_array;
my $json = JSON->new;
if ( ref( $args->{q} ) eq 'ARRAY' ) {
foreach my $q ( @{ $args->{q} } ) {
push @query_params_array, $json->decode($q)
if $q;
}
}
my $metric_types = $query_params_array[0][0]->{'erm_usage_titles.erm_usage_muses.metric_type'};
my @usage_data_provider_report_data;
for my $usage_data_provider ( @{ $usage_data_providers } ) {
# Split usage_data_providers into metric_types i.e. one table row per metric_type
for my $metric_type ( @$metric_types ) {
my @filtered_title_data;
for my $title ( @{ $usage_data_provider->{'erm_usage_titles'} }) {
my $statistics = $title->{'erm_usage_muses'};
my @filtered_statistics = grep { $metric_type eq $_->{metric_type} } @$statistics;
my %title_hash = (
usage_data_provider_id => $title->{usage_data_provider_id},
title_id => $title->{title_id},
title => $title->{title},
erm_usage_muses => \@filtered_statistics,
online_issn => $title->{online_issn},
print_issn => $title->{print_issn},
title_doi => $title->{title_doi},
title_uri => $title->{title_uri},
metric_type => $metric_type,
publisher => $title->{publisher},
publisher_id => $title->{publisher_id},
);
push @filtered_title_data, \%title_hash;
}
my %usage_data_provider_hash = (
erm_usage_data_provider_id => $usage_data_provider->{erm_usage_data_provider_id},
erm_usage_titles => \@filtered_title_data,
aggregator => $usage_data_provider->{aggregator},
api_key => $usage_data_provider->{api_key},
begin_date => $usage_data_provider->{begin_date},
customer_id => $usage_data_provider->{customer_id},
description => $usage_data_provider->{description},
end_date => $usage_data_provider->{end_date},
method => $usage_data_provider->{method},
name => $usage_data_provider->{name},
report_release => $usage_data_provider->{report_release},
report_types => $usage_data_provider->{report_types},
requestor_email => $usage_data_provider->{requestor_email},
requestor_id => $usage_data_provider->{requestor_id},
requestor_name => $usage_data_provider->{requestor_name},
service_type => $usage_data_provider->{service_type},
service_url => $usage_data_provider->{service_url},
metric_type => $metric_type
);
push @usage_data_provider_report_data, \%usage_data_provider_hash;
};
};
return $c->render( status => 200, openapi => \@usage_data_provider_report_data );
}
catch {
$c->unhandled_exception($_);
};
}
1;

View file

@ -85,11 +85,21 @@ properties:
type:
- string
- "null"
metric_type:
description: metric type of the harvester when reporting
type:
- string
- "null"
counter_files:
type: array
description: counter files
items:
$ref: erm_counter_file.yaml
erm_usage_titles:
type: array
description: usage titles
items:
$ref: erm_usage_title.yaml
additionalProperties: false
required:

View file

@ -103,6 +103,7 @@
type: string
enum:
- counter_files
- erm_usage_titles.erm_usage_muses
collectionFormat: csv
- $ref: "../swagger.yaml#/parameters/match"
- $ref: "../swagger.yaml#/parameters/order_by"
@ -217,6 +218,9 @@
type: array
items:
type: string
enum:
- counter_files
- erm_usage_titles.erm_usage_muses
collectionFormat: csv
responses:
200:
@ -416,7 +420,7 @@
operationId: testUsageDataProviderHarvester
tags:
- usage data provider harvester
summary: Run this data provider's harvester
summary: Test this data provider's harvester
produces:
- application/json
parameters:
@ -445,6 +449,60 @@
description: Under maintenance
schema:
$ref: "../swagger.yaml#/definitions/error"
x-koha-authorization:
permissions:
erm: 1
"/erm/usage_data_providers/report":
get:
x-mojo-to: ERM::UsageDataProviders#providers_report
operationId: reportUsageDataProvider
tags:
- usage data provider report
summary: Run a report for this data provider
produces:
- application/json
parameters:
- $ref: "../swagger.yaml#/parameters/match"
- $ref: "../swagger.yaml#/parameters/order_by"
- $ref: "../swagger.yaml#/parameters/page"
- $ref: "../swagger.yaml#/parameters/per_page"
- $ref: "../swagger.yaml#/parameters/q_param"
- $ref: "../swagger.yaml#/parameters/q_body"
- $ref: "../swagger.yaml#/parameters/q_header"
- name: x-koha-embed
in: header
required: false
description: Embed list sent as a request header
type: array
items:
type: string
enum:
- counter_files
- erm_usage_titles.erm_usage_muses
responses:
200:
description: Successful report run
schema:
items:
$ref: "../swagger.yaml#/definitions/erm_usage_data_provider"
400:
description: Bad request
schema:
$ref: "../swagger.yaml#/definitions/error"
403:
description: Access forbidden
schema:
$ref: "../swagger.yaml#/definitions/error"
500:
description: |-
Internal server error. Possible `error_code` attribute values:
* `internal_server_error`
schema:
$ref: "../swagger.yaml#/definitions/error"
503:
description: Under maintenance
schema:
$ref: "../swagger.yaml#/definitions/error"
x-koha-authorization:
permissions:
erm: 1

View file

@ -297,6 +297,8 @@ paths:
$ref: "./paths/erm_usage_data_providers.yaml#/~1erm~1usage_data_providers~1{erm_usage_data_provider_id}~1run"
"/erm/usage_data_providers/{erm_usage_data_provider_id}/test_connection":
$ref: "./paths/erm_usage_data_providers.yaml#/~1erm~1usage_data_providers~1{erm_usage_data_provider_id}~1test_connection"
"/erm/usage_data_providers/report":
$ref: "./paths/erm_usage_data_providers.yaml#/~1erm~1usage_data_providers~1report"
/erm/usage_titles:
$ref: ./paths/erm_usage_titles.yaml#/~1erm~1usage_titles
/erm/users:

View file

@ -30,6 +30,10 @@
value: 'metric_type',
description: 'By metric type',
},
{
value: 'usage_data_provider',
description: 'By data provider totals',
},
]"
/>
</li>
@ -637,10 +641,24 @@ export default {
this.time_period_columns_builder = time_period_columns
},
buildMonthlyUrlQuery(query, time_period_columns, metric_type_report) {
let url = metric_type_report
? "/api/v1/erm/usage_titles/metric_types_report"
: "/api/v1/erm/usage_titles/monthly_report"
buildMonthlyUrlQuery(query, time_period_columns, data_display) {
let url
let prefix
switch (data_display) {
case "monthly":
url = "/api/v1/erm/usage_titles/monthly_report"
prefix = "erm_usage_muses"
break
case "metric_type":
url = "/api/v1/erm/usage_titles/metric_types_report"
prefix = "erm_usage_muses"
break
case "usage_data_provider":
url = "/api/v1/erm/usage_data_providers/report"
prefix = "erm_usage_titles.erm_usage_muses"
break
}
// Work out which years are included in the query
const years = []
const {
@ -665,8 +683,8 @@ export default {
const queryArray = years.map(year => {
const queryByYear = {}
queryByYear[`erm_usage_muses.year`] = year
queryByYear[`erm_usage_muses.report_type`] = report_type
queryByYear[`${prefix}.year`] = year
queryByYear[`${prefix}.report_type`] = report_type
// Find the months applicable to each year, ignoring months that have been de-selected
const queryMonths = months[year]
@ -674,21 +692,21 @@ export default {
.map(month => {
return month.value
})
queryByYear[`erm_usage_muses.month`] = queryMonths
queryByYear[`${prefix}.month`] = queryMonths
// Add any title query
if (titles) {
const title_ids = titles.map(title => {
return title.title_id
})
queryByYear[`erm_usage_muses.title_id`] = title_ids
queryByYear[`${prefix}.title_id`] = title_ids
}
// Add any metric types query
if (metric_types) {
queryByYear[`erm_usage_muses.metric_type`] = metric_types
queryByYear[`${prefix}.metric_type`] = metric_types
}
// Add any data provider query
if (usage_data_providers) {
queryByYear[`erm_usage_muses.usage_data_provider_id`] =
queryByYear[`${prefix}.usage_data_provider_id`] =
usage_data_providers
}
@ -889,19 +907,18 @@ export default {
queryObject.metric_types = final_metric_types
}
const metric_report_type =
data_display === "metric_type" ? true : false
const url = !data_display.includes("yearly")
? this.buildMonthlyUrlQuery(
queryObject,
this.time_period_columns_builder,
metric_report_type
data_display
)
: this.buildYearlyUrlQuery(queryObject)
const type = data_display
const columns = this.defineColumns(
this.title_property_column_options
)
const columns =
data_display === "usage_data_provider"
? []
: this.defineColumns(this.title_property_column_options)
const yearly_filter = data_display.includes("monthly")
? this.yearly_filter_required
: false

View file

@ -47,6 +47,20 @@ export default {
this.report_type === "yearly"
? ["erm_usage_yuses"]
: ["erm_usage_muses"]
switch (this.report_type) {
case "monthly":
this.embed = "erm_usage_muses"
break
case "yearly":
this.embed = "erm_usage_yuses"
break
case "metric_type":
this.embed = "erm_usage_muses"
break
case "usage_data_provider":
this.embed = "erm_usage_titles.erm_usage_muses"
break
}
this.years = Object.keys(this.params.tp_columns)
this.year = this.years[this.years.length - 1]
@ -78,15 +92,16 @@ export default {
const yearly_filter = params.yearly_filter
const query = params.queryObject
const column_set = [
{
const column_set = [...columns]
report_type !== "usage_data_provider" &&
column_set.unshift({
title: __("Title"),
data: "title",
searchable: true,
orderable: true,
},
...columns,
]
})
// Add metric type to each row
if (report_type !== "metric_type") {
column_set.push({
@ -99,6 +114,36 @@ export default {
})
}
if (report_type === "usage_data_provider") {
column_set.unshift({
title: __("Data provider"),
data: "name",
searchable: true,
orderable: true,
})
column_set.push({
title: __("Period Total"),
render: function (data, type, row, meta) {
const sum = row.erm_usage_titles.reduce(
(acc, title) => {
const titleSum = title.erm_usage_muses.reduce(
(acc, mus) => {
return acc + mus.usage_count
},
0
)
return acc + titleSum
},
0
)
return sum
},
searchable: true,
orderable: true,
})
return column_set
}
// Add monthly columns
if (yearly_filter) {
months_data.forEach(month => {
@ -307,8 +352,6 @@ export default {
},
watch: {
table() {
// table needs to be rendered before header can be created and
// table is hidden by .hide-table until table header is created
if (this.report_type !== "metric_type") {
this.mergeTitleDataIntoOneLine(
this.params.queryObject.metric_types.length