Bugzilla – Attachment 90065 Details for
Bug 22818
ILL should be able to send notices
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 22818: Add generation and sending of notices
Bug-22818-Add-generation-and-sending-of-notices.patch (text/plain), 23.40 KB, created by
Andrew Isherwood
on 2019-05-24 15:38:27 UTC
(
hide
)
Description:
Bug 22818: Add generation and sending of notices
Filename:
MIME Type:
Creator:
Andrew Isherwood
Created:
2019-05-24 15:38:27 UTC
Size:
23.40 KB
patch
obsolete
>From 0644937cc38a18a984556a9124884cb20e2b4f82 Mon Sep 17 00:00:00 2001 >From: Andrew Isherwood <andrew.isherwood@ptfs-europe.com> >Date: Wed, 8 May 2019 10:42:22 +0100 >Subject: [PATCH] Bug 22818: Add generation and sending of notices > >This patch adds the ability for ILL to send notices, both triggered by >staff and triggered by events. > >Staff can trigger notices to patrons from the "Manage ILL request" screen: >- ILL request ready for pickup >- ILL request unavailable >- Place request with partners > >The following notices to staff are triggered automatically: >- Request has been modified by patron >- Request has been cancelled by patron > >Branches can now specify an "ILL email" address to which notices >intended to inform staff of changes to requests by patrons can be sent. > >The sending of notices is controlled by a few new sysprefs: >- "ILLDefaultStaffEmail" - Fallback email address for staff ILL notices >to be sent to in the absence of a branch address >- "ILLSendStaffNotices" - To specify which staff notices should be sent >automatically when requests are manipulated by patrons > >Patron notices are also controlled by the patron's messaging >preferences >--- > Koha/Illrequest.pm | 351 ++++++++++++++++----- > Koha/Illrequest/Logger.pm | 41 ++- > ill/ill-requests.pl | 36 ++- > .../prog/en/modules/ill/ill-requests.tt | 39 +++ > .../prog/en/modules/ill/log/patron_notice.tt | 6 + > opac/opac-illrequests.pl | 2 + > 6 files changed, 402 insertions(+), 73 deletions(-) > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/ill/log/patron_notice.tt > >diff --git a/Koha/Illrequest.pm b/Koha/Illrequest.pm >index 14c4ce7c91..5775308899 100644 >--- a/Koha/Illrequest.pm >+++ b/Koha/Illrequest.pm >@@ -27,6 +27,8 @@ use Mail::Sendmail; > use Try::Tiny; > use DateTime; > >+use C4::Letters; >+use C4::Members; > use Koha::Database; > use Koha::Email; > use Koha::Exceptions::Ill; >@@ -243,6 +245,7 @@ sub status_alias { > > Overloaded getter/setter for request status, > also nullifies status_alias and records the fact that the status has changed >+and sends a notice if appropriate > > =cut > >@@ -276,6 +279,10 @@ sub status { > }); > } > delete $self->{previous_status}; >+ # If status has changed to cancellation requested, send a notice >+ if ($new_status eq 'CANCREQ') { >+ $self->send_staff_notice('ILL_REQUEST_CANCEL'); >+ } > return $ret; > } else { > return $current_status; >@@ -1039,38 +1046,12 @@ sub generic_confirm { > my $branch = Koha::Libraries->find($params->{current_branchcode}) > || die "Invalid current branchcode. Are you logged in as the database user?"; > if ( !$params->{stage}|| $params->{stage} eq 'init' ) { >- my $draft->{subject} = "ILL Request"; >- $draft->{body} = <<EOF; >-Dear Sir/Madam, >- >- We would like to request an interlibrary loan for a title matching the >-following description: >- >-EOF >- >- my $details = $self->metadata; >- while (my ($title, $value) = each %{$details}) { >- $draft->{body} .= " - " . $title . ": " . $value . "\n" >- if $value; >- } >- $draft->{body} .= <<EOF; >- >-Please let us know if you are able to supply this to us. >- >-Kind Regards >- >-EOF > >- my @address = map { $branch->$_ } >- qw/ branchname branchaddress1 branchaddress2 branchaddress3 >- branchzip branchcity branchstate branchcountry branchphone >- branchillemail branchemail /; >- my $address = ""; >- foreach my $line ( @address ) { >- $address .= $line . "\n" if $line; >- } >- >- $draft->{body} .= $address; >+ # Get the message body from the notice definition >+ my $letter = $self->get_notice({ >+ notice_code => 'ILL_PARTNER_REQ', >+ transport => 'email' >+ }); > > my $partners = Koha::Patrons->search({ > categorycode => $self->_config->partner_code >@@ -1082,7 +1063,10 @@ EOF > method => 'generic_confirm', > stage => 'draft', > value => { >- draft => $draft, >+ draft => { >+ subject => $letter->{title}, >+ body => $letter->{content} >+ }, > partners => $partners, > } > }; >@@ -1098,57 +1082,282 @@ EOF > "No target email addresses found. Either select at least one partner or check your ILL partner library records.") > if ( !$to ); > # Create the from, replyto and sender headers >- my $from = $branch->branchemail; >+ my $from = $branch->branchillemail || $branch->branchemail; > my $replyto = $branch->branchreplyto || $from; > Koha::Exceptions::Ill::NoLibraryEmail->throw( > "Your library has no usable email address. Please set it.") > if ( !$from ); > >- # Create the email >- my $message = Koha::Email->new; >- my %mail = $message->create_message_headers( >- { >- to => $to, >- from => $from, >- replyto => $replyto, >- subject => Encode::encode( "utf8", $params->{subject} ), >- message => Encode::encode( "utf8", $params->{body} ), >- contenttype => 'text/plain', >+ # So we get a notice hashref, then substitute the possibly >+ # modified title and body from the draft stage >+ my $letter = $self->get_notice({ >+ notice_code => 'ILL_PARTNER_REQ', >+ transport => 'email' >+ }); >+ $letter->{title} = $params->{subject}; >+ $letter->{content} = $params->{body}; >+ >+ # Send the email >+ my $params = { >+ letter => $letter, >+ borrowernumber => $self->borrowernumber, >+ message_transport_type => 'email', >+ to_address => $to, >+ from_address => $from >+ }; >+ >+ if ($letter) { >+ my $result = C4::Letters::EnqueueLetter($params); >+ if ( $result ) { >+ $self->status("GENREQ")->store; >+ $self->_backend_capability( >+ 'set_requested_partners', >+ { >+ request => $self, >+ to => $to >+ } >+ ); >+ return { >+ error => 0, >+ status => '', >+ message => '', >+ method => 'generic_confirm', >+ stage => 'commit', >+ next => 'illview', >+ }; > } >- ); >- # Send it >- my $result = sendmail(%mail); >- if ( $result ) { >- $self->status("GENREQ")->store; >- $self->_backend_capability( >- 'set_requested_partners', >- { >- request => $self, >- to => $to >- } >- ); >- return { >- error => 0, >- status => '', >- message => '', >- method => 'generic_confirm', >- stage => 'commit', >- next => 'illview', >- }; >- } else { >- return { >- error => 1, >- status => 'email_failed', >- message => $Mail::Sendmail::error, >- method => 'generic_confirm', >- stage => 'draft', >- }; > } >+ return { >+ error => 1, >+ status => 'email_failed', >+ message => 'Email queueing failed', >+ method => 'generic_confirm', >+ stage => 'draft', >+ }; > } else { > die "Unknown stage, should not have happened." > } > } > >+=head3 get_staff_to_address >+ >+ my $email = $request->get_staff_to_address(); >+ >+Get the email address to which staff notices should be sent >+ >+=cut >+ >+sub get_staff_to_address { >+ my ( $self ) = @_; >+ >+ # The various places we can get an ILL staff email address from >+ # (In order of preference) >+ # >+ # Dedicated branch address >+ my $library = Koha::Libraries->find( $self->branchcode ); >+ my $branch_ill_to = $library->branchillemail; >+ # General purpose ILL address from syspref >+ my $syspref = C4::Context->preference("ILLDefaultStaffEmail"); >+ # Branch general email address >+ my $branch_to = $library->branchemail; >+ # Last resort >+ my $koha_admin = C4::Context->preference('KohaAdminEmailAddress'); >+ >+ my $to; >+ if ($branch_ill_to) { >+ $to = $branch_ill_to; >+ } elsif ($syspref) { >+ $to = $syspref; >+ } elsif ($branch_to) { >+ $to = $branch_to; >+ } elsif ($koha_admin) { >+ $to = $koha_admin; >+ } >+ >+ # $to will not be defined if we didn't find a usable address >+ return $to; >+} >+ >+=head3 send_patron_notice >+ >+ my $result = $request->send_patron_notice($notice_code); >+ >+Send a specified notice regarding this request to a patron >+ >+=cut >+ >+sub send_patron_notice { >+ my ( $self, $notice_code ) = @_; >+ >+ # We need a notice code >+ if (!$notice_code) { >+ return { >+ error => 'notice_no_type' >+ }; >+ } >+ >+ # Map from the notice code to the messaging preference >+ my %message_name = ( >+ ILL_PICKUP_READY => 'Ill_ready', >+ ILL_REQUEST_UNAVAIL => 'Ill_unavailable' >+ ); >+ >+ # Get the patron's messaging preferences >+ my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences({ >+ borrowernumber => $self->borrowernumber, >+ message_name => $message_name{$notice_code} >+ }); >+ my @transports = keys %{ $borrower_preferences->{transports} }; >+ >+ # Send the notice to the patron via the chosen transport methods >+ # and record the results >+ my @success = (); >+ my @fail = (); >+ for my $transport (@transports) { >+ my $letter = $self->get_notice({ >+ notice_code => $notice_code, >+ transport => $transport >+ }); >+ if ($letter) { >+ my $result = C4::Letters::EnqueueLetter({ >+ letter => $letter, >+ borrowernumber => $self->borrowernumber, >+ message_transport_type => $transport, >+ }); >+ if ($result) { >+ push @success, $transport; >+ } else { >+ push @fail, $transport; >+ } >+ } else { >+ push @fail, $transport; >+ } >+ } >+ if (scalar @success > 0) { >+ my $logger = Koha::Illrequest::Logger->new; >+ $logger->log_patron_notice({ >+ request => $self, >+ notice_code => $notice_code >+ }); >+ } >+ return { >+ result => { >+ success => \@success, >+ fail => \@fail >+ } >+ }; >+} >+ >+=head3 send_staff_notice >+ >+ my $result = $request->send_staff_notice($notice_code); >+ >+Send a specified notice regarding this request to staff >+ >+=cut >+ >+sub send_staff_notice { >+ my ( $self, $notice_code ) = @_; >+ >+ # We need a notice code >+ if (!$notice_code) { >+ return { >+ error => 'notice_no_type' >+ }; >+ } >+ >+ # Get the staff notices that have been assigned for sending in >+ # the syspref >+ my $staff_to_send = C4::Context->preference('ILLSendStaffNotices'); >+ >+ # If it hasn't been enabled in the syspref, we don't want to send it >+ if ($staff_to_send !~ /\b$notice_code\b/) { >+ return { >+ error => 'notice_not_enabled' >+ }; >+ } >+ >+ my $letter = $self->get_notice({ >+ notice_code => $notice_code, >+ transport => 'email' >+ }); >+ >+ # Try and get an address to which to send staff notices >+ my $to_address = scalar $self->get_staff_to_address; >+ >+ my $params = { >+ letter => $letter, >+ borrowernumber => $self->borrowernumber, >+ message_transport_type => 'email', >+ }; >+ >+ if ($to_address) { >+ $params->{to_address} = $to_address; >+ $params->{from_address} = $to_address; >+ } else { >+ return { >+ error => 'notice_no_create' >+ }; >+ } >+ >+ if ($letter) { >+ C4::Letters::EnqueueLetter($params) >+ or warn "can't enqueue letter $letter"; >+ return { >+ success => 'notice_queued' >+ }; >+ } else { >+ return { >+ error => 'notice_no_create' >+ }; >+ } >+} >+ >+=head3 get_notice >+ >+ my $notice = $request->get_notice($params); >+ >+Return a compiled notice hashref for the passed notice code >+and transport type >+ >+=cut >+ >+sub get_notice { >+ my ( $self, $params ) = @_; >+ >+ my $title = $self->illrequestattributes->find( >+ { type => 'title' } >+ ); >+ my $author = $self->illrequestattributes->find( >+ { type => 'author' } >+ ); >+ my $metahash = $self->metadata; >+ my @metaarray = (); >+ while (my($key, $value) = each %{$metahash}) { >+ push @metaarray, "- $key: $value" if $value; >+ } >+ my $metastring = join("\n", @metaarray); >+ my $letter = C4::Letters::GetPreparedLetter( >+ module => 'ill', >+ letter_code => $params->{notice_code}, >+ message_transport_type => $params->{transport}, >+ lang => $self->patron->lang, >+ tables => { >+ illrequests => $self->illrequest_id, >+ borrowers => $self->borrowernumber, >+ biblio => $self->biblio_id, >+ branches => $self->branchcode, >+ }, >+ substitute => { >+ ill_bib_title => $title ? $title->value : 'N/A', >+ ill_bib_author => $author ? $author->value : 'N/A', >+ ill_full_metadata => $metastring >+ } >+ ); >+ >+ return $letter; >+} >+ > =head3 id_prefix > > my $prefix = $record->id_prefix; >diff --git a/Koha/Illrequest/Logger.pm b/Koha/Illrequest/Logger.pm >index 0625370237..0faa134ec9 100644 >--- a/Koha/Illrequest/Logger.pm >+++ b/Koha/Illrequest/Logger.pm >@@ -26,6 +26,7 @@ use C4::Context; > use C4::Templates; > use C4::Log qw( logaction ); > use Koha::ActionLogs; >+use Koha::Notice::Template; > > =head1 NAME > >@@ -62,6 +63,9 @@ sub new { > $self->{loggers} = { > status => sub { > $self->log_status_change(@_); >+ }, >+ patron_notice => sub { >+ $self->log_patron_notice(@_); > } > }; > >@@ -69,7 +73,8 @@ sub new { > C4::Templates::_get_template_file('ill/log/', 'intranet'); > > $self->{templates} = { >- STATUS_CHANGE => $base . 'status_change.tt' >+ STATUS_CHANGE => $base . 'status_change.tt', >+ PATRON_NOTICE => $base . 'patron_notice.tt' > }; > > bless $self, $class; >@@ -102,6 +107,31 @@ sub log_maybe { > } > } > >+=head3 log_patron_notice >+ >+ Koha::IllRequest::Logger->log_patron_notice($params); >+ >+Receive a hashref containing a request object and params to log, >+and log it >+ >+=cut >+ >+sub log_patron_notice { >+ my ( $self, $params ) = @_; >+ >+ if (defined $params->{request} && defined $params->{notice_code}) { >+ $self->log_something({ >+ modulename => 'ILL', >+ actionname => 'PATRON_NOTICE', >+ objectnumber => $params->{request}->id, >+ infos => to_json({ >+ log_origin => 'core', >+ notice_code => $params->{notice_code} >+ }) >+ }); >+ } >+} >+ > =head3 log_status_change > > Koha::IllRequest::Logger->log_status_change($params); >@@ -209,6 +239,14 @@ sub get_request_logs { > { order_by => { -desc => "timestamp" } } > )->unblessed; > >+ # Populate a lookup table for all ILL notice types >+ my $notice_types = Koha::Notice::Templates->search({ >+ module => 'ill' >+ })->unblessed; >+ my $notice_hash; >+ foreach my $notice(@{$notice_types}) { >+ $notice_hash->{$notice->{code}} = $notice; >+ } > # Populate a lookup table for status aliases > my $aliases = GetAuthorisedValues('ILLSTATUS'); > my $alias_hash; >@@ -216,6 +254,7 @@ sub get_request_logs { > $alias_hash->{$alias->{authorised_value}} = $alias; > } > foreach my $log(@{$logs}) { >+ $log->{notice_types} = $notice_hash; > $log->{aliases} = $alias_hash; > $log->{info} = from_json($log->{info}); > $log->{template} = $self->get_log_template({ >diff --git a/ill/ill-requests.pl b/ill/ill-requests.pl >index 010c61e618..e8137121f9 100755 >--- a/ill/ill-requests.pl >+++ b/ill/ill-requests.pl >@@ -23,6 +23,7 @@ use CGI; > > use C4::Auth; > use C4::Output; >+use Koha::Notice::Templates; > use Koha::AuthorisedValues; > use Koha::Illcomment; > use Koha::Illrequests; >@@ -70,12 +71,28 @@ if ( $backends_available ) { > # View the details of an ILL > my $request = Koha::Illrequests->find($params->{illrequest_id}); > >+ # Get the details for notices that can be sent from here >+ my $notices = Koha::Notice::Templates->search( >+ { >+ module => 'ill', >+ code => { -in => [ 'ILL_PICKUP_READY' ,'ILL_REQUEST_UNAVAIL' ] }, >+ }, >+ { >+ columns => [ qw/code name/ ], >+ distinct => 1 >+ } >+ )->unblessed; >+ > $template->param( >+ notices => $notices, > request => $request, > csrf_token => Koha::Token->new->generate_csrf({ > session_id => scalar $cgi->cookie('CGISESSID'), > }), >- ( $params->{error} ? ( error => $params->{error} ) : () ), >+ ( $params->{tran_error} ? >+ ( tran_error => $params->{tran_error} ) : () ), >+ ( $params->{tran_success} ? >+ ( tran_success => $params->{tran_success} ) : () ), > ); > > } elsif ( $op eq 'create' ) { >@@ -306,6 +323,23 @@ if ( $backends_available ) { > ); > exit; > >+ } elsif ( $op eq "send_notice" ) { >+ my $illrequest_id = $params->{illrequest_id}; >+ my $request = Koha::Illrequests->find($illrequest_id); >+ my $ret = $request->send_patron_notice($params->{notice_code}); >+ my $append = ''; >+ if ($ret->{result} && scalar @{$ret->{result}->{success}} > 0) { >+ $append .= '&tran_success=' . join(',', @{$ret->{result}->{success}}); >+ } >+ if ($ret->{result} && scalar @{$ret->{result}->{fail}} > 0) { >+ $append .= '&tran_fail=' . join(',', @{$ret->{result}->{fail}}.join(',')); >+ } >+ # Redirect to view the whole request >+ print $cgi->redirect( >+ "/cgi-bin/koha/ill/ill-requests.pl?method=illview&illrequest_id=". >+ scalar $params->{illrequest_id} . $append >+ ); >+ exit; > } else { > my $request = Koha::Illrequests->find($params->{illrequest_id}); > my $backend_result = $request->custom_capability($op, $params); >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt >index 88ee777a09..32a6d772f0 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt >@@ -92,6 +92,10 @@ > </p> > [% END %] > >+ [% IF whole.success %] >+ <p>[% whole.success | html %]</p> >+ [% END %] >+ > [% IF query_type == 'create' %] > <h1>New ILL request</h1> > [% PROCESS $whole.template %] >@@ -279,6 +283,31 @@ > [% END %] > [% END %] > >+ [% IF tran_success %] >+ [% succ_methods = [] %] >+ [% IF tran_success.match('email') %] >+ [% succ_methods.push('email') %] >+ [% END %] >+ [% IF tran_success.match('sms') %] >+ [% succ_methods.push('SMS') %] >+ [% END %] >+ <div class="alert"> >+ The requested notice was queued for delivery by [% succ_methods.join(', ') | html %] >+ </div> >+ [% END %] >+ [% IF tran_fail %] >+ [% fail_methods = [] %] >+ [% IF tran_fail.match('email') %] >+ [% fail_methods.push('email') %] >+ [% END %] >+ [% IF tran_fail.match('sms') %] >+ [% fail_methods.push('SMS') %] >+ [% END %] >+ <div class="alert"> >+ The requested notice was NOT queued for delivery by [% fail_methods.join(', ') | html %] >+ </div> >+ [% END %] >+ > <h1>Manage ILL request</h1> > <div id="request-toolbar" class="btn-toolbar"> > <a title="Edit request" id="ill-toolbar-btn-edit-action" class="btn btn-default" href="/cgi-bin/koha/ill/ill-requests.pl?method=edit_action&illrequest_id=[% request.illrequest_id | html %]"> >@@ -317,6 +346,16 @@ > </a> > [% END %] > [% END %] >+ <div class="dropdown btn-group"> >+ <button class="btn btn-default dropdown-toggle" type="button" id="ill-notice-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> >+ <i class="fa fa-envelope"></i> Send notice to patron <span class="caret"></span> >+ </button> >+ <ul class="dropdown-menu" aria-labelledby="ill-notice-dropdown"> >+ [% FOREACH notice IN notices %] >+ <li><a href="/cgi-bin/koha/ill/ill-requests.pl?method=send_notice&illrequest_id=[% request.illrequest_id | uri %]&notice_code=[% notice.code | uri %]">[% notice.name | html %]</a></li> >+ [% END %] >+ </ul> >+ </div> > <a title="Display supplier metadata" id="ill-request-display-metadata" class="btn btn-default pull-right" href="#"> > <span class="fa fa-eye"></span> > Display supplier metadata >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/log/patron_notice.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/log/patron_notice.tt >new file mode 100644 >index 0000000000..7628789623 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/ill/log/patron_notice.tt >@@ -0,0 +1,6 @@ >+[% USE KohaDates %] >+<p> >+[% log.timestamp | $KohaDates with_hours => 1 %] : <b>Patron notice sent: </b> >+[% notice_code = log.info.notice_code %] >+"[% log.notice_types.$notice_code.name | html %]" >+</p> >diff --git a/opac/opac-illrequests.pl b/opac/opac-illrequests.pl >index f35b19ada9..ab804140d2 100755 >--- a/opac/opac-illrequests.pl >+++ b/opac/opac-illrequests.pl >@@ -83,6 +83,8 @@ if ( $op eq 'list' ) { > illrequest_id => $params->{illrequest_id} > }); > $request->notesopac($params->{notesopac})->store; >+ # Send a notice to staff alerting them of the update >+ $request->send_staff_notice('ILL_REQUEST_MODIFIED'); > print $query->redirect( > '/cgi-bin/koha/opac-illrequests.pl?method=view&illrequest_id=' . > $params->{illrequest_id} . >-- >2.11.0
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 22818
:
89831
|
89832
|
89833
|
89834
|
89835
|
90063
|
90064
|
90065
|
90066
|
90067
|
90715
|
90716
|
90717
|
90718
|
90719
|
92898
|
92899
|
92900
|
92901
|
92902
|
100234
|
100235
|
100236
|
100237
|
100238
|
103268
|
103269
|
103270
|
103271
|
103272
|
106424
|
106425
|
106426
|
106427
|
106428
|
106675
|
106676
|
106677
|
106678
|
106679
|
106680
|
106681
|
106691
|
106693
|
106694
|
106704
|
106705
|
106706
|
106707
|
106708
|
106709
|
106710
|
106711
|
106712
|
106713
|
110196
|
110197
|
110198
|
110199
|
110201
|
110202
|
110203
|
110204
|
110205
|
110206
|
110207
|
110208
|
111837
|
111838
|
111839
|
111840
|
111841
|
111842
|
111843
|
111844
|
111845
|
111846
|
111847
|
111848
|
111874
|
111880
|
111881
|
111883
|
111884
|
111885
|
111886
|
111887
|
111888
|
111889
|
111890
|
111891
|
111892
|
111893
|
111897
|
111899
|
111900
|
111901
|
111902
|
111903
|
111904
|
111905
|
111906
|
111907
|
111908
|
111909
|
111910
|
111911
|
111912
|
111913
|
113398
|
113399
|
113400
|
113401
|
113402
|
113403
|
113404
|
113405
|
113406
|
113407
|
113408
|
113409
|
113410
|
113411
|
113412
|
113413
|
113463
|
113464
|
113465
|
113466
|
113467
|
113468
|
113469
|
113470
|
113471
|
113472
|
113473
|
113474
|
113475
|
113476
|
113477
|
113478
|
113479
|
113522
|
113549
|
113584