Bugzilla – Attachment 144298 Details for
Bug 30719
ILL should provide the ability to create batch requests
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 30719: DB, API & tests
Bug-30719-DB-API--tests.patch (text/plain), 42.98 KB, created by
Pedro Amorim
on 2022-11-28 17:42:01 UTC
(
hide
)
Description:
Bug 30719: DB, API & tests
Filename:
MIME Type:
Creator:
Pedro Amorim
Created:
2022-11-28 17:42:01 UTC
Size:
42.98 KB
patch
obsolete
>From 7c98b4571fabdb4f1aa8e8858933254a509200e6 Mon Sep 17 00:00:00 2001 >From: Andrew Isherwood <andrew.isherwood@ptfs-europe.com> >Date: Wed, 11 May 2022 13:34:58 +0100 >Subject: [PATCH] Bug 30719: DB, API & tests > >This commit adds the following: > >- A database update that adds an "illbatches" table, a >"illrequest.batch_id" foreign key and an "illbatches.borrowernumber" >foreign key >- Illbatch and Illbatches Koha objects >- Adds 'batch' accessor to Illrequest object >- CRUD API endpoints for working with ILL batches >- Unit tests of the Koha objects and API endpoints >- Adds 'batch_id' filter to /illrequests endpoint > >Signed-off-by: Pedro Amorim <pedro.amorim@ptfs-europe.com> >--- > Koha/Illbatch.pm | 95 ++++ > Koha/Illbatches.pm | 61 +++ > Koha/Illrequest.pm | 18 + > Koha/REST/V1/Illbatches.pm | 219 +++++++++ > Koha/REST/V1/Illrequests.pm | 5 +- > api/v1/swagger/definitions/illbatch.yaml | 39 ++ > api/v1/swagger/definitions/illbatches.yaml | 5 + > api/v1/swagger/paths/illbatches.yaml | 232 ++++++++++ > api/v1/swagger/paths/illrequests.yaml | 5 + > api/v1/swagger/swagger.yaml | 17 + > .../atomicupdate/bug_30719_add_ill_batches.pl | 38 ++ > installer/data/mysql/kohastructure.sql | 20 +- > t/db_dependent/Illbatches.t | 96 ++++ > t/db_dependent/api/v1/illbatches.t | 417 ++++++++++++++++++ > 14 files changed, 1265 insertions(+), 2 deletions(-) > create mode 100644 Koha/Illbatch.pm > create mode 100644 Koha/Illbatches.pm > create mode 100644 Koha/REST/V1/Illbatches.pm > create mode 100644 api/v1/swagger/definitions/illbatch.yaml > create mode 100644 api/v1/swagger/definitions/illbatches.yaml > create mode 100644 api/v1/swagger/paths/illbatches.yaml > create mode 100755 installer/data/mysql/atomicupdate/bug_30719_add_ill_batches.pl > create mode 100755 t/db_dependent/Illbatches.t > create mode 100755 t/db_dependent/api/v1/illbatches.t > >diff --git a/Koha/Illbatch.pm b/Koha/Illbatch.pm >new file mode 100644 >index 0000000000..edb2feb029 >--- /dev/null >+++ b/Koha/Illbatch.pm >@@ -0,0 +1,95 @@ >+package Koha::Illbatch; >+ >+# Copyright PTFS Europe 2022 >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+use Koha::Database; >+use base qw(Koha::Object); >+ >+=head1 NAME >+ >+Koha::Illbatch - Koha Illbatch Object class >+ >+=head2 Class methods >+ >+=head3 patron >+ >+ my $patron = Koha::Illbatch->patron; >+ >+Return the patron object associated with this batch >+ >+=cut >+ >+sub patron { >+ my ( $self ) = @_; >+ return Koha::Patron->_new_from_dbic( >+ scalar $self->_result->borrowernumber >+ ); >+} >+ >+=head3 branch >+ >+ my $branch = Koha::Illbatch->branch; >+ >+Return the branch object associated with this batch >+ >+=cut >+ >+sub branch { >+ my ( $self ) = @_; >+ return Koha::Library->_new_from_dbic( >+ scalar $self->_result->branchcode >+ ); >+} >+ >+=head3 requests_count >+ >+ my $requests_count = Koha::Illbatch->requests_count; >+ >+Return the number of requests associated with this batch >+ >+=cut >+ >+sub requests_count { >+ my ( $self ) = @_; >+ return Koha::Illrequests->search({ >+ batch_id => $self->id >+ })->count; >+} >+ >+=head2 Internal methods >+ >+=head3 _type >+ >+ my $type = Koha::Illbatch->_type; >+ >+Return this object's type >+ >+=cut >+ >+sub _type { >+ return 'Illbatch'; >+} >+ >+=head1 AUTHOR >+ >+Andrew Isherwood <andrew.isherwood@ptfs-europe.com> >+ >+=cut >+ >+1; >diff --git a/Koha/Illbatches.pm b/Koha/Illbatches.pm >new file mode 100644 >index 0000000000..ee65a262d6 >--- /dev/null >+++ b/Koha/Illbatches.pm >@@ -0,0 +1,61 @@ >+package Koha::Illbatches; >+ >+# Copyright PTFS Europe 2022 >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+use Koha::Database; >+use Koha::Illbatch; >+use base qw(Koha::Objects); >+ >+=head1 NAME >+ >+Koha::Illbatches - Koha Illbatches Object class >+ >+=head2 Internal methods >+ >+=head3 _type >+ >+ my $type = Koha::Illbatches->_type; >+ >+Return this object's type >+ >+=cut >+ >+sub _type { >+ return 'Illbatch'; >+} >+ >+=head3 object_class >+ >+ my $class = Koha::Illbatches->object_class; >+ >+Return this object's class name >+ >+=cut >+ >+sub object_class { >+ return 'Koha::Illbatch'; >+} >+ >+=head1 AUTHOR >+ >+Andrew Isherwood <andrew.isherwood@ptfs-europe.com> >+ >+=cut >+ >+1; >diff --git a/Koha/Illrequest.pm b/Koha/Illrequest.pm >index 723b11843e..063a3dd2da 100644 >--- a/Koha/Illrequest.pm >+++ b/Koha/Illrequest.pm >@@ -32,6 +32,7 @@ use Koha::Illrequestattributes; > use Koha::AuthorisedValue; > use Koha::Illrequest::Logger; > use Koha::Patron; >+use Koha::Illbatches; > use Koha::AuthorisedValues; > use Koha::Biblios; > use Koha::Items; >@@ -143,6 +144,23 @@ sub push_processor { > push @{$self->{processors}}, $processor; > } > >+=head3 batch >+ >+ my $batch = $request->batch; >+ >+Returns the batch associated with a request >+ >+=cut >+ >+sub batch { >+ my ( $self ) = @_; >+ >+ return Koha::Illbatches->find($self->_result->batch_id); >+# return Koha::Illbatch->_new_from_dbic( >+# scalar $self->_result->batch_id >+# ); >+} >+ > =head3 statusalias > > my $statusalias = $request->statusalias; >diff --git a/Koha/REST/V1/Illbatches.pm b/Koha/REST/V1/Illbatches.pm >new file mode 100644 >index 0000000000..af21e762ae >--- /dev/null >+++ b/Koha/REST/V1/Illbatches.pm >@@ -0,0 +1,219 @@ >+package Koha::REST::V1::Illbatches; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+ >+use Koha::Illbatches; >+use Koha::Illrequests; >+ >+=head1 NAME >+ >+Koha::REST::V1::Illbatches >+ >+=head2 Operations >+ >+=head3 list >+ >+Return a list of available ILL batches >+ >+=cut >+ >+sub list { >+ my $c = shift->openapi->valid_input; >+ >+ my @batches = Koha::Illbatches->search()->as_list; >+ >+ # Get all patrons associated with all our batches >+ # in one go >+ my $patrons = {}; >+ foreach my $batch(@batches) { >+ my $patron_id = $batch->borrowernumber; >+ $patrons->{$patron_id} = 1 >+ }; >+ my @patron_ids = keys %{$patrons}; >+ my $patron_results = Koha::Patrons->search({ >+ borrowernumber => { -in => \@patron_ids } >+ }); >+ >+ # Get all branches associated with all our batches >+ # in one go >+ my $branches = {}; >+ foreach my $batch(@batches) { >+ my $branch_id = $batch->branchcode; >+ $branches->{$branch_id} = 1 >+ }; >+ my @branchcodes = keys %{$branches}; >+ my $branch_results = Koha::Libraries->search({ >+ branchcode => { -in => \@branchcodes } >+ }); >+ >+ # Populate the response >+ my @to_return = (); >+ foreach my $it_batch(@batches) { >+ my $patron = $patron_results->find({ borrowernumber => $it_batch->borrowernumber}); >+ my $branch = $branch_results->find({ branchcode => $it_batch->branchcode }); >+ push @to_return, { >+ %{$it_batch->unblessed}, >+ patron => $patron, >+ branch => $branch, >+ requests_count => $it_batch->requests_count >+ }; >+ } >+ >+ return $c->render( status => 200, openapi => \@to_return ); >+} >+ >+=head3 get >+ >+Get one batch >+ >+=cut >+ >+sub get { >+ my $c = shift->openapi->valid_input; >+ >+ my $batchid = $c->validation->param('illbatch_id'); >+ >+ my $batch = Koha::Illbatches->find($batchid); >+ >+ if (not defined $batch) { >+ return $c->render( >+ status => 404, >+ openapi => { error => "ILL batch not found" } >+ ); >+ } >+ >+ return $c->render( >+ status => 200, >+ openapi => { >+ %{$batch->unblessed}, >+ patron => $batch->patron->unblessed, >+ branch => $batch->branch->unblessed, >+ requests_count => $batch->requests_count >+ } >+ ); >+} >+ >+=head3 add >+ >+Add a new batch >+ >+=cut >+ >+sub add { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $body = $c->validation->param('body'); >+ >+ # We receive cardnumber, so we need to look up the corresponding >+ # borrowernumber >+ my $patron = Koha::Patrons->find({ cardnumber => $body->{cardnumber} }); >+ delete $body->{cardnumber}; >+ $body->{borrowernumber} = $patron->borrowernumber; >+ >+ return try { >+ my $batch = Koha::Illbatch->new( $body ); >+ $batch->store; >+ $c->res->headers->location( $c->req->url->to_string . '/' . $batch->id ); >+ >+ my $ret = { >+ %{$batch->unblessed}, >+ patron => $batch->patron->unblessed, >+ branch => $batch->branch->unblessed, >+ requests_count => 0 >+ }; >+ >+ return $c->render( >+ status => 201, >+ openapi => $ret >+ ); >+ } >+ catch { >+ $c->unhandled_exception($_); >+ }; >+} >+ >+=head3 update >+ >+Update a batch >+ >+=cut >+ >+sub update { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $batch = Koha::Illbatches->find( $c->validation->param('illbatch_id') ); >+ >+ if ( not defined $batch ) { >+ return $c->render( >+ status => 404, >+ openapi => { error => "ILL batch not found" } >+ ); >+ } >+ >+ my $params = $c->req->json; >+ delete $params->{cardnumber}; >+ >+ return try { >+ $batch->set( $params ); >+ $batch->store(); >+ >+ my $ret = { >+ %{$batch->unblessed}, >+ patron => $batch->patron->unblessed, >+ branch => $batch->branch->unblessed, >+ requests_count => $batch->requests_count >+ }; >+ >+ return $c->render( >+ status => 200, >+ openapi => $ret >+ ); >+ } >+ catch { >+ $c->unhandled_exception($_); >+ }; >+} >+ >+=head3 delete >+ >+Delete a batch >+ >+=cut >+ >+sub delete { >+ >+ my $c = shift->openapi->valid_input or return; >+ >+ my $batch = Koha::Illbatches->find( $c->validation->param( 'illbatch_id' ) ); >+ >+ if ( not defined $batch ) { >+ return $c->render( status => 404, openapi => { error => "ILL batch not found" } ); >+ } >+ >+ return try { >+ $batch->delete; >+ return $c->render( status => 204, openapi => ''); >+ } >+ catch { >+ $c->unhandled_exception($_); >+ }; >+} >+ >+1; >diff --git a/Koha/REST/V1/Illrequests.pm b/Koha/REST/V1/Illrequests.pm >index 82c5b5dd08..e3fa0a2363 100644 >--- a/Koha/REST/V1/Illrequests.pm >+++ b/Koha/REST/V1/Illrequests.pm >@@ -61,13 +61,16 @@ sub list { > my $hidden_statuses = [ split /\|/, $hidden_statuses_string ]; > > # Get all requests >- # If necessary, only get those from a specified patron >+ # If necessary, restrict the resultset > my @requests = Koha::Illrequests->search({ > $hidden_statuses > ? ( status => { 'not in' => $hidden_statuses } ) > : (), > $args->{borrowernumber} > ? ( borrowernumber => $args->{borrowernumber} ) >+ : (), >+ $args->{batch_id} >+ ? ( batch_id => $args->{batch_id} ) > : () > })->as_list; > >diff --git a/api/v1/swagger/definitions/illbatch.yaml b/api/v1/swagger/definitions/illbatch.yaml >new file mode 100644 >index 0000000000..2248beae54 >--- /dev/null >+++ b/api/v1/swagger/definitions/illbatch.yaml >@@ -0,0 +1,39 @@ >+--- >+type: object >+properties: >+ id: >+ type: string >+ description: Internal ILL batch identifier >+ name: >+ type: string >+ description: Name of the ILL batch >+ backend: >+ type: string >+ description: Backend name >+ cardnumber: >+ type: string >+ description: Card number of the patron of the ILL batch >+ borrowernumber: >+ type: string >+ description: Borrower number of the patron of the ILL batch >+ branchcode: >+ type: string >+ description: Branch code of the branch of the ILL batch >+ patron: >+ type: >+ - object >+ - "null" >+ description: The patron associated with the batch >+ branch: >+ type: >+ - object >+ - "null" >+ description: The branch associated with the batch >+ requests_count: >+ type: string >+ description: The number of requests in this batch >+additionalProperties: false >+required: >+ - name >+ - backend >+ - branchcode >\ No newline at end of file >diff --git a/api/v1/swagger/definitions/illbatches.yaml b/api/v1/swagger/definitions/illbatches.yaml >new file mode 100644 >index 0000000000..4db20f480d >--- /dev/null >+++ b/api/v1/swagger/definitions/illbatches.yaml >@@ -0,0 +1,5 @@ >+--- >+type: array >+items: >+ $ref: "illbatch.yaml" >+additionalProperties: false >diff --git a/api/v1/swagger/paths/illbatches.yaml b/api/v1/swagger/paths/illbatches.yaml >new file mode 100644 >index 0000000000..d19df76f75 >--- /dev/null >+++ b/api/v1/swagger/paths/illbatches.yaml >@@ -0,0 +1,232 @@ >+--- >+/illbatches: >+ get: >+ x-mojo-to: Illbatches#list >+ operationId: listIllbatches >+ tags: >+ - illbatches >+ summary: List ILL batches >+ parameters: [] >+ produces: >+ - application/json >+ responses: >+ "200": >+ description: A list of ILL batches >+ schema: >+ $ref: "../swagger.yaml#/definitions/illbatches" >+ "401": >+ description: Authentication required >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "404": >+ description: ILL batches not found >+ 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: >+ ill: "1" >+ post: >+ x-mojo-to: Illbatches#add >+ operationId: addIllbatch >+ tags: >+ - illbatches >+ summary: Add ILL batch >+ parameters: >+ - name: body >+ in: body >+ description: A JSON object containing informations about the new batch >+ required: true >+ schema: >+ $ref: "../swagger.yaml#/definitions/illbatch" >+ produces: >+ - application/json >+ responses: >+ "201": >+ description: Batch added >+ schema: >+ $ref: "../swagger.yaml#/definitions/illbatch" >+ "400": >+ description: Bad request >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "401": >+ description: Authentication required >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "409": >+ description: Conflict in creating resource >+ 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: >+ ill: "1" >+"/illbatches/{illbatch_id}": >+ get: >+ x-mojo-to: Illbatches#get >+ operationId: getIllbatches >+ tags: >+ - illbatches >+ summary: Get ILL batch >+ parameters: >+ - name: illbatch_id >+ in: path >+ description: ILL batch id/name/contents >+ required: true >+ type: string >+ produces: >+ - application/json >+ responses: >+ "200": >+ description: An ILL batch >+ schema: >+ $ref: "../swagger.yaml#/definitions/illbatch" >+ "401": >+ description: Authentication required >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "404": >+ description: ILL batch not found >+ 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: >+ ill: "1" >+ put: >+ x-mojo-to: Illbatches#update >+ operationId: updateIllBatch >+ tags: >+ - illbatches >+ summary: Update batch >+ parameters: >+ - $ref: "../swagger.yaml#/parameters/illbatch_id_pp" >+ - name: body >+ in: body >+ description: A JSON object containing information on the batch >+ required: true >+ schema: >+ $ref: "../swagger.yaml#/definitions/illbatch" >+ consumes: >+ - application/json >+ produces: >+ - application/json >+ responses: >+ "200": >+ description: An ILL batch >+ schema: >+ $ref: "../swagger.yaml#/definitions/illbatch" >+ "400": >+ description: Bad request >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "401": >+ description: Authentication required >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "404": >+ description: ILL batch not found >+ 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: >+ ill: "1" >+ delete: >+ x-mojo-to: Illbatches#delete >+ operationId: deleteBatch >+ tags: >+ - illbatches >+ summary: Delete ILL batch >+ parameters: >+ - $ref: "../swagger.yaml#/parameters/illbatch_id_pp" >+ produces: >+ - application/json >+ responses: >+ "204": >+ description: ILL batch deleted >+ schema: >+ type: string >+ "401": >+ description: Authentication required >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "404": >+ description: ILL batch not found >+ 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: >+ ill: "1" >diff --git a/api/v1/swagger/paths/illrequests.yaml b/api/v1/swagger/paths/illrequests.yaml >index 1e3224bda0..92725f08b1 100644 >--- a/api/v1/swagger/paths/illrequests.yaml >+++ b/api/v1/swagger/paths/illrequests.yaml >@@ -38,6 +38,11 @@ > description: Internal biblio identifier > required: false > type: integer >+ - name: batch_id >+ in: query >+ description: Internal identifier of the batch the request belongs to >+ required: false >+ type: integer > - name: borrowernumber > in: query > description: Internal patron identifier >diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml >index 696a73be8b..873463a001 100644 >--- a/api/v1/swagger/swagger.yaml >+++ b/api/v1/swagger/swagger.yaml >@@ -48,6 +48,10 @@ definitions: > $ref: ./definitions/ill_backend.yaml > ill_backends: > $ref: ./definitions/ill_backends.yaml >+ illbatch: >+ $ref: ./definitions/illbatch.yaml >+ illbatches: >+ $ref: ./definitions/illbatches.yaml > import_batch_profile: > $ref: ./definitions/import_batch_profile.yaml > import_batch_profiles: >@@ -225,6 +229,10 @@ paths: > $ref: ./paths/ill_backends.yaml#/~1ill_backends > "/ill_backends/{ill_backend_id}": > $ref: "./paths/ill_backends.yaml#/~1ill_backends~1{ill_backend_id}" >+ /illbatches: >+ $ref: ./paths/illbatches.yaml#/~1illbatches >+ "/illbatches/{illbatch_id}": >+ $ref: "./paths/illbatches.yaml#/~1illbatches~1{illbatch_id}" > /illrequests: > $ref: ./paths/illrequests.yaml#/~1illrequests > "/import_batches/{import_batch_id}/records/{import_record_id}/matches/chosen": >@@ -420,6 +428,12 @@ parameters: > name: hold_id > required: true > type: integer >+ illbatch_id_pp: >+ description: Internal ILL batch identifier >+ in: path >+ name: illbatch_id >+ required: true >+ type: integer > import_batch_profile_id_pp: > description: Internal profile identifier > in: path >@@ -713,6 +727,9 @@ tags: > - description: "Manage ILL module backends\n" > name: illbackends > x-displayName: ILL backends >+ - description: "Manage ILL module batches\n" >+ name: illbatches >+ x-displayName: ILL batches > - description: "Manage ILL requests\n" > name: illrequests > x-displayName: ILL requests >diff --git a/installer/data/mysql/atomicupdate/bug_30719_add_ill_batches.pl b/installer/data/mysql/atomicupdate/bug_30719_add_ill_batches.pl >new file mode 100755 >index 0000000000..0d8846c694 >--- /dev/null >+++ b/installer/data/mysql/atomicupdate/bug_30719_add_ill_batches.pl >@@ -0,0 +1,38 @@ >+use Modern::Perl; >+ >+return { >+ bug_number => "30719", >+ description => "Add ILL batches", >+ up => sub { >+ my ($args) = @_; >+ my ($dbh, $out) = @$args{qw(dbh out)}; >+ $dbh->do(q{ >+ CREATE TABLE `illbatches` ( >+ `id` int(11) NOT NULL auto_increment, -- Batch ID >+ `name` varchar(100) NOT NULL, -- Unique name of batch >+ `backend` varchar(20) NOT NULL, -- Name of batch backend >+ `borrowernumber` int(11), -- Patron associated with batch >+ `branchcode` varchar(50), -- Branch associated with batch >+ PRIMARY KEY (`id`), >+ UNIQUE KEY `u_illbatches__name` (`name`) >+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci >+ }); >+ $dbh->do(q{ >+ ALTER TABLE `illrequests` >+ ADD COLUMN `batch_id` int(11) AFTER backend -- Optional ID of batch that this request belongs to >+ }); >+ $dbh->do(q{ >+ ALTER TABLE `illrequests` >+ ADD CONSTRAINT `illrequests_ibfk` FOREIGN KEY (`batch_id`) REFERENCES `illbatches` (`id`) ON DELETE SET NULL ON UPDATE CASCADE >+ }); >+ $dbh->do(q{ >+ ALTER TABLE `illbatches` >+ ADD CONSTRAINT `illbatches_bnfk` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE >+ }); >+ $dbh->do(q{ >+ ALTER TABLE `illbatches` >+ ADD CONSTRAINT `illbatches_bcfk` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE SET NULL ON UPDATE CASCADE >+ }); >+ say $out "Bug 30719: Add ILL batches completed" >+ }, >+}; >diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql >index d831006cd5..ad05b24458 100644 >--- a/installer/data/mysql/kohastructure.sql >+++ b/installer/data/mysql/kohastructure.sql >@@ -3227,6 +3227,22 @@ CREATE TABLE `illrequestattributes` ( > ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; > /*!40101 SET character_set_client = @saved_cs_client */; > >+-- >+-- Table structure for table `illbatches` >+-- >+DROP TABLE IF EXISTS `illbatches`; >+CREATE TABLE `illbatches` ( >+ `id` int(11) NOT NULL auto_increment, -- Batch ID >+ `name` varchar(100) NOT NULL, -- Unique name of batch >+ `backend` varchar(20) NOT NULL, -- Name of batch backend >+ `borrowernumber` int(11), -- Patron associated with batch >+ `branchcode` varchar(50), -- Branch associated with batch >+ PRIMARY KEY (`id`), >+ UNIQUE KEY `u_illbatches__name` (`name`), >+ CONSTRAINT `illbatches_bnfk` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE SET NULL ON UPDATE CASCADE, >+ CONSTRAINT `illbatches_bcfk` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE SET NULL ON UPDATE CASCADE >+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; >+ > -- > -- Table structure for table `illrequests` > -- >@@ -3254,13 +3270,15 @@ CREATE TABLE `illrequests` ( > `notesstaff` mediumtext DEFAULT NULL COMMENT 'Staff notes attached to request', > `orderid` varchar(50) DEFAULT NULL COMMENT 'Backend id attached to request', > `backend` varchar(20) DEFAULT NULL COMMENT 'The backend used to create request', >+ `batch_id` int(11) COMMENT 'Optional ID of batch that this request belongs to', > PRIMARY KEY (`illrequest_id`), > KEY `illrequests_bnfk` (`borrowernumber`), > KEY `illrequests_bcfk_2` (`branchcode`), > KEY `illrequests_safk` (`status_alias`), > CONSTRAINT `illrequests_bcfk_2` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE, > CONSTRAINT `illrequests_bnfk` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE CASCADE ON UPDATE CASCADE, >- CONSTRAINT `illrequests_safk` FOREIGN KEY (`status_alias`) REFERENCES `authorised_values` (`authorised_value`) ON DELETE SET NULL ON UPDATE CASCADE >+ CONSTRAINT `illrequests_safk` FOREIGN KEY (`status_alias`) REFERENCES `authorised_values` (`authorised_value`) ON DELETE SET NULL ON UPDATE CASCADE, >+ CONSTRAINT `illrequests_ibfk` FOREIGN KEY (`batch_id`) REFERENCES `illbatches` (`id`) ON DELETE SET NULL ON UPDATE CASCADE > ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; > /*!40101 SET character_set_client = @saved_cs_client */; > >diff --git a/t/db_dependent/Illbatches.t b/t/db_dependent/Illbatches.t >new file mode 100755 >index 0000000000..0d28a8f44b >--- /dev/null >+++ b/t/db_dependent/Illbatches.t >@@ -0,0 +1,96 @@ >+#s!/usr/bin/perl >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use File::Basename qw/basename/; >+use Koha::Database; >+use Koha::Illbatch; >+use Koha::Illbatches; >+use Koha::Illrequests; >+use Koha::Patrons; >+use t::lib::Mocks; >+use t::lib::TestBuilder; >+use Test::MockObject; >+use Test::MockModule; >+ >+use Test::More tests => 8; >+ >+my $schema = Koha::Database->new->schema; >+my $builder = t::lib::TestBuilder->new; >+use_ok('Koha::Illbatch'); >+use_ok('Koha::Illbatches'); >+ >+$schema->storage->txn_begin; >+ >+Koha::Illrequests->search->delete; >+ >+# Create a patron >+my $patron = $builder->build({ source => 'Borrower' }); >+ >+# Create a librarian >+my $librarian = $builder->build({ >+ source => 'Borrower', >+ value => { >+ firstname => "Grogu" >+ } >+}); >+ >+# Create a branch >+my $branch = $builder->build({ >+ source => 'Branch' >+}); >+ >+# Create a batch >+my $illbatch = $builder->build({ >+ source => 'Illbatch', >+ value => { >+ name => "My test batch", >+ backend => "Mock", >+ borrowernumber => $librarian->{borrowernumber}, >+ branchcode => $branch->{branchcode} >+ } >+}); >+my $batch_obj = Koha::Illbatches->find($illbatch->{id}); >+isa_ok( $batch_obj, 'Koha::Illbatch' ); >+ >+# Create an ILL request in the batch >+my $illrq = $builder->build({ >+ source => 'Illrequest', >+ value => { >+ borrowernumber => $patron->{borrowernumber}, >+ batch_id => $illbatch->{id} >+ } >+}); >+my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id}); >+ >+# Check requests_count >+my $requests_count = $batch_obj->requests_count; >+is( $requests_count, 1, 'requests_count returns correctly' ); >+ >+# Check patron >+my $batch_patron = $batch_obj->patron; >+isa_ok( $batch_patron, 'Koha::Patron' ); >+is( $batch_patron->firstname, "Grogu", "patron returns correctly" ); >+ >+# Check branch >+my $batch_branch = $batch_obj->branch; >+isa_ok( $batch_branch, 'Koha::Library' ); >+is( $batch_branch->branchcode, $branch->{branchcode}, "branch returns correctly" ); >+ >+$illrq_obj->delete; >+$schema->storage->txn_rollback; >diff --git a/t/db_dependent/api/v1/illbatches.t b/t/db_dependent/api/v1/illbatches.t >new file mode 100755 >index 0000000000..4e7512fadd >--- /dev/null >+++ b/t/db_dependent/api/v1/illbatches.t >@@ -0,0 +1,417 @@ >+#!/usr/bin/env perl >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Test::More tests => 5; >+use Test::Mojo; >+ >+use t::lib::TestBuilder; >+use t::lib::Mocks; >+ >+use Koha::Illbatch; >+use Koha::Illbatches; >+use Koha::Illrequests; >+use Koha::Database; >+ >+my $schema = Koha::Database->new->schema; >+my $builder = t::lib::TestBuilder->new; >+ >+my $t = Test::Mojo->new('Koha::REST::V1'); >+t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); >+ >+subtest 'list() tests' => sub { >+ >+ plan tests => 19; >+ >+ $schema->storage->txn_begin; >+ >+ Koha::Illbatches->search->delete; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { >+ flags => 2 ** 22 # 22 => ill >+ } >+ } >+ ); >+ >+ my $branch = $builder->build_object( >+ { >+ class => 'Koha::Libraries' >+ } >+ ); >+ >+ my $password = 'sheev_is_da_boss!'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ ## Authorized user tests >+ # No batches, so empty array should be returned >+ $t->get_ok("//$userid:$password@/api/v1/illbatches") >+ ->status_is(200) >+ ->json_is( [] ); >+ >+ my $batch = $builder->build_object({ >+ class => 'Koha::Illbatches', >+ value => { >+ name => "PapaPalpatine", >+ backend => "Mock", >+ borrowernumber => $librarian->borrowernumber, >+ branchcode => $branch->branchcode >+ } >+ }); >+ >+ my $illrq = $builder->build({ >+ source => 'Illrequest', >+ value => { >+ borrowernumber => $librarian->borrowernumber, >+ batch_id => $batch->id >+ } >+ }); >+ >+ # One batch created, should get returned >+ $t->get_ok("//$userid:$password@/api/v1/illbatches") >+ ->status_is(200) >+ ->json_has( '/0/id', 'Batch ID' ) >+ ->json_has( '/0/name', 'Batch name' ) >+ ->json_has( '/0/backend', 'Backend name' ) >+ ->json_has( '/0/borrowernumber', 'Borrowernumber' ) >+ ->json_has( '/0/branchcode', 'Branchcode' ) >+ ->json_has( '/0/patron', 'patron embedded' ) >+ ->json_has( '/0/branch', 'branch embedded' ) >+ ->json_has( '/0/requests_count', 'request count' ); >+ >+ # Try to create a second batch with the same name, this should fail >+ my $another_batch = $builder->build_object({ class => 'Koha::Illbatches', value => { >+ name => $batch->name >+ } }); >+ # Create a second batch with a different name >+ my $batch_with_another_name = $builder->build_object({ class => 'Koha::Illbatches' }); >+ >+ # Two batches created, they should both be returned >+ $t->get_ok("//$userid:$password@/api/v1/illbatches") >+ ->status_is(200) >+ ->json_has('/0', 'has first batch') >+ ->json_has('/1', 'has second batch'); >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { >+ cardnumber => 999, >+ flags => 0 >+ } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ # Unauthorized access >+ $t->get_ok("//$unauth_userid:$password@/api/v1/illbatches") >+ ->status_is(403); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'get() tests' => sub { >+ >+ plan tests => 15; >+ >+ $schema->storage->txn_begin; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 2**22 } # 22 => ill >+ } >+ ); >+ my $password = 'Rebelz4DaWin'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ my $branch = $builder->build_object( >+ { >+ class => 'Koha::Libraries' >+ } >+ ); >+ >+ my $batch = $builder->build_object({ >+ class => 'Koha::Illbatches', >+ value => { >+ name => "LeiaOrgana", >+ backend => "Mock", >+ borrowernumber => $librarian->borrowernumber, >+ branchcode => $branch->branchcode >+ } >+ }); >+ >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ $t->get_ok( "//$userid:$password@/api/v1/illbatches/" . $batch->id ) >+ ->status_is(200) >+ ->json_has( '/id', 'Batch ID' ) >+ ->json_has( '/name', 'Batch name' ) >+ ->json_has( '/backend', 'Backend name' ) >+ ->json_has( '/borrowernumber', 'Borrowernumber' ) >+ ->json_has( '/branchcode', 'Branchcode' ) >+ ->json_has( '/patron', 'patron embedded' ) >+ ->json_has( '/branch', 'branch embedded' ) >+ ->json_has( '/requests_count', 'request count' ); >+ >+ $t->get_ok( "//$unauth_userid:$password@/api/v1/illbatches/" . $batch->id ) >+ ->status_is(403); >+ >+ my $batch_to_delete = $builder->build_object({ class => 'Koha::Illbatches' }); >+ my $non_existent_id = $batch_to_delete->id; >+ $batch_to_delete->delete; >+ >+ $t->get_ok( "//$userid:$password@/api/v1/illbatches/$non_existent_id" ) >+ ->status_is(404) >+ ->json_is( '/error' => 'ILL batch not found' ); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'add() tests' => sub { >+ >+ plan tests =>16; >+ >+ $schema->storage->txn_begin; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 2**22 } # 22 => ill >+ } >+ ); >+ my $password = 'v4d3rRox'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ my $branch = $builder->build_object( >+ { >+ class => 'Koha::Libraries' >+ } >+ ); >+ >+ my $batch_metadata = { >+ name => "Anakin's requests", >+ backend => "Mock", >+ borrowernumber => $librarian->borrowernumber, >+ branchcode => $branch->branchcode >+ }; >+ >+ # Unauthorized attempt to write >+ $t->post_ok("//$unauth_userid:$password@/api/v1/illbatches" => json => $batch_metadata) >+ ->status_is(403); >+ >+ # Authorized attempt to write invalid data >+ my $batch_with_invalid_field = { >+ %{$batch_metadata}, >+ doh => 1 >+ }; >+ >+ $t->post_ok( "//$userid:$password@/api/v1/illbatches" => json => $batch_with_invalid_field ) >+ ->status_is(400) >+ ->json_is( >+ "/errors" => [ >+ { >+ message => "Properties not allowed: doh.", >+ path => "/body" >+ } >+ ] >+ ); >+ >+ # Authorized attempt to write >+ my $batch_id = >+ $t->post_ok( "//$userid:$password@/api/v1/illbatches" => json => $batch_metadata ) >+ ->status_is( 201 ) >+ ->json_is( '/name' => $batch_metadata->{name} ) >+ ->json_is( '/backend' => $batch_metadata->{backend} ) >+ ->json_is( '/borrowernumber' => $batch_metadata->{borrowernumber} ) >+ ->json_is( '/branchcode' => $batch_metadata->{branchcode} ) >+ ->json_has( '/patron' ) >+ ->json_has( '/branch' ); >+ >+ # Authorized attempt to create with null id >+ $batch_metadata->{id} = undef; >+ $t->post_ok( "//$userid:$password@/api/v1/illbatches" => json => $batch_metadata ) >+ ->status_is(400) >+ ->json_has('/errors'); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'update() tests' => sub { >+ >+ plan tests => 15; >+ >+ $schema->storage->txn_begin; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 2**22 } # 22 => ill >+ } >+ ); >+ my $password = 'aw3s0m3y0d41z'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ my $branch = $builder->build_object( >+ { >+ class => 'Koha::Libraries' >+ } >+ ); >+ >+ my $batch_id = $builder->build_object({ class => 'Koha::Illbatches' } )->id; >+ >+ # Unauthorized attempt to update >+ $t->put_ok( "//$unauth_userid:$password@/api/v1/illbatches/$batch_id" => json => { name => 'These are not the droids you are looking for' } ) >+ ->status_is(403); >+ >+ # Attempt partial update on a PUT >+ my $batch_with_missing_field = { >+ backend => "Mock", >+ borrowernumber => $librarian->borrowernumber, >+ branchcode => $branch->branchcode >+ }; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/illbatches/$batch_id" => json => $batch_with_missing_field ) >+ ->status_is(400) >+ ->json_is( "/errors" => >+ [ { message => "Missing property.", path => "/body/name" } ] >+ ); >+ >+ # Full object update on PUT >+ my $batch_with_updated_field = { >+ name => "Master Ploo Koon", >+ backend => "Mock", >+ borrowernumber => $librarian->borrowernumber, >+ branchcode => $branch->branchcode >+ }; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/illbatches/$batch_id" => json => $batch_with_updated_field ) >+ ->status_is(200) >+ ->json_is( '/name' => 'Master Ploo Koon' ); >+ >+ # Authorized attempt to write invalid data >+ my $batch_with_invalid_field = { >+ doh => 1, >+ name => "Master Mace Windu", >+ backend => "Mock" >+ }; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/illbatches/$batch_id" => json => $batch_with_invalid_field ) >+ ->status_is(400) >+ ->json_is( >+ "/errors" => [ >+ { >+ message => "Properties not allowed: doh.", >+ path => "/body" >+ } >+ ] >+ ); >+ >+ my $batch_to_delete = $builder->build_object({ class => 'Koha::Cities' }); >+ my $non_existent_id = $batch_to_delete->id; >+ $batch_to_delete->delete; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/illbatches/$non_existent_id" => json => $batch_with_updated_field ) >+ ->status_is(404); >+ >+ # Wrong method (POST) >+ $batch_with_updated_field->{id} = 2; >+ >+ $t->post_ok( "//$userid:$password@/api/v1/illbatches/$batch_id" => json => $batch_with_updated_field ) >+ ->status_is(404); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'delete() tests' => sub { >+ >+ plan tests => 6; >+ >+ $schema->storage->txn_begin; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 2**22 } # 22 => ill >+ } >+ ); >+ my $password = 's1th43v3r!'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ my $batch_id = $builder->build_object({ class => 'Koha::Illbatches' })->id; >+ >+ # Unauthorized attempt to delete >+ $t->delete_ok( "//$unauth_userid:$password@/api/v1/illbatches/$batch_id" ) >+ ->status_is(403); >+ >+ $t->delete_ok("//$userid:$password@/api/v1/illbatches/$batch_id") >+ ->status_is(204); >+ >+ $t->delete_ok("//$userid:$password@/api/v1/illbatches/$batch_id") >+ ->status_is(404); >+ >+ $schema->storage->txn_rollback; >+}; >-- >2.25.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 30719
:
144281
|
144285
|
144286
|
144287
|
144288
|
144289
|
144290
|
144291
|
144292
|
144293
|
144294
|
144295
|
144296
|
144297
|
144298
|
144299
|
144300
|
144301
|
144302
|
145760
|
145869
|
145870
|
145876
|
145934
|
146152
|
147658
|
147929
|
147930
|
147931
|
147932
|
147933
|
147934
|
147952
|
147953
|
147954
|
147955
|
147956
|
151152
|
151153
|
151154
|
151155
|
151156
|
151284
|
151285
|
151286
|
151287
|
151288
|
151303
|
151304
|
151305
|
151306
|
151307
|
151308
|
151309
|
151310
|
151311
|
151312
|
151513
|
151514
|
151515
|
151516
|
151517
|
151519
|
151520
|
151521
|
151522
|
151523
|
151571
|
151572
|
151573
|
151574
|
151575
|
151611
|
151612
|
151613
|
151614
|
151615
|
151804
|
151805
|
151806
|
151807
|
151808
|
151809
|
154046
|
154047
|
154048
|
154049
|
154050
|
154051
|
154052
|
155421
|
155422
|
155423
|
155424
|
155425
|
155426
|
155427
|
155428
|
155429
|
155430
|
155431
|
155432
|
155433
|
155434
|
155435
|
156556
|
156748
|
156749
|
156752
|
156783
|
156785
|
156811
|
156812
|
156827
|
156828