Bug 20600: Add filtering of ILL requests in list
[koha.git] / Koha / Illrequest.pm
blobff834f14f589acbea4dc0ec1244b1a7bd773cc61
1 package Koha::Illrequest;
3 # Copyright PTFS Europe 2016
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 3 of the License, or (at your option) any later
10 # version.
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 # details.
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 51 Franklin
19 # Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 use Modern::Perl;
23 use Clone 'clone';
24 use File::Basename qw( basename );
25 use Encode qw( encode );
26 use Mail::Sendmail;
27 use Try::Tiny;
29 use Koha::Database;
30 use Koha::Email;
31 use Koha::Exceptions::Ill;
32 use Koha::Illcomments;
33 use Koha::Illrequestattributes;
34 use Koha::Patron;
36 use base qw(Koha::Object);
38 =head1 NAME
40 Koha::Illrequest - Koha Illrequest Object class
42 =head1 (Re)Design
44 An ILLRequest consists of two parts; the Illrequest Koha::Object, and a series
45 of related Illrequestattributes.
47 The former encapsulates the basic necessary information that any ILL requires
48 to be usable in Koha. The latter is a set of additional properties used by
49 one of the backends.
51 The former subsumes the legacy "Status" object. The latter remains
52 encapsulated in the "Record" object.
54 TODO:
56 - Anything invoking the ->status method; annotated with:
57 + # Old use of ->status !
59 =head1 API
61 =head2 Backend API Response Principles
63 All methods should return a hashref in the following format:
65 =over
67 =item * error
69 This should be set to 1 if an error was encountered.
71 =item * status
73 The status should be a string from the list of statuses detailed below.
75 =item * message
77 The message is a free text field that can be passed on to the end user.
79 =item * value
81 The value returned by the method.
83 =back
85 =head2 Interface Status Messages
87 =over
89 =item * branch_address_incomplete
91 An interface request has determined branch address details are incomplete.
93 =item * cancel_success
95 The interface's cancel_request method was successful in cancelling the
96 Illrequest using the API.
98 =item * cancel_fail
100 The interface's cancel_request method failed to cancel the Illrequest using
101 the API.
103 =item * unavailable
105 The interface's request method returned saying that the desired item is not
106 available for request.
108 =back
110 =head2 Class methods
112 =head3 illrequestattributes
114 =cut
116 sub illrequestattributes {
117 my ( $self ) = @_;
118 return Koha::Illrequestattributes->_new_from_dbic(
119 scalar $self->_result->illrequestattributes
123 =head3 illcomments
125 =cut
127 sub illcomments {
128 my ( $self ) = @_;
129 return Koha::Illcomments->_new_from_dbic(
130 scalar $self->_result->illcomments
134 =head3 patron
136 =cut
138 sub patron {
139 my ( $self ) = @_;
140 return Koha::Patron->_new_from_dbic(
141 scalar $self->_result->borrowernumber
145 =head3 load_backend
147 Require "Base.pm" from the relevant ILL backend.
149 =cut
151 sub load_backend {
152 my ( $self, $backend_id ) = @_;
154 my @raw = qw/Koha Illbackends/; # Base Path
156 my $backend_name = $backend_id || $self->backend;
158 unless ( defined $backend_name && $backend_name ne '' ) {
159 Koha::Exceptions::Ill::InvalidBackendId->throw(
160 "An invalid backend ID was requested ('')");
163 my $location = join "/", @raw, $backend_name, "Base.pm"; # File to load
164 my $backend_class = join "::", @raw, $backend_name, "Base"; # Package name
165 require $location;
166 $self->{_my_backend} = $backend_class->new({ config => $self->_config });
167 return $self;
171 =head3 _backend
173 my $backend = $abstract->_backend($new_backend);
174 my $backend = $abstract->_backend;
176 Getter/Setter for our API object.
178 =cut
180 sub _backend {
181 my ( $self, $backend ) = @_;
182 $self->{_my_backend} = $backend if ( $backend );
183 # Dynamically load our backend object, as late as possible.
184 $self->load_backend unless ( $self->{_my_backend} );
185 return $self->{_my_backend};
188 =head3 _backend_capability
190 my $backend_capability_result = $self->_backend_capability($name, $args);
192 This is a helper method to invoke optional capabilities in the backend. If
193 the capability named by $name is not supported, return 0, else invoke it,
194 passing $args along with the invocation, and return its return value.
196 NOTE: this module suffers from a confusion in termninology:
198 in _backend_capability, the notion of capability refers to an optional feature
199 that is implemented in core, but might not be supported by a given backend.
201 in capabilities & custom_capability, capability refers to entries in the
202 status_graph (after union between backend and core).
204 The easiest way to fix this would be to fix the terminology in
205 capabilities & custom_capability and their callers.
207 =cut
209 sub _backend_capability {
210 my ( $self, $name, $args ) = @_;
211 my $capability = 0;
212 try {
213 $capability = $self->_backend->capabilities($name);
214 } catch {
215 return 0;
217 if ( $capability ) {
218 return &{$capability}($args);
219 } else {
220 return 0;
224 =head3 _config
226 my $config = $abstract->_config($config);
227 my $config = $abstract->_config;
229 Getter/Setter for our config object.
231 =cut
233 sub _config {
234 my ( $self, $config ) = @_;
235 $self->{_my_config} = $config if ( $config );
236 # Load our config object, as late as possible.
237 unless ( $self->{_my_config} ) {
238 $self->{_my_config} = Koha::Illrequest::Config->new;
240 return $self->{_my_config};
243 =head3 metadata
245 =cut
247 sub metadata {
248 my ( $self ) = @_;
249 return $self->_backend->metadata($self);
252 =head3 _core_status_graph
254 my $core_status_graph = $illrequest->_core_status_graph;
256 Returns ILL module's default status graph. A status graph defines the list of
257 available actions at any stage in the ILL workflow. This is for instance used
258 by the perl script & template to generate the correct buttons to display to
259 the end user at any given point.
261 =cut
263 sub _core_status_graph {
264 my ( $self ) = @_;
265 return {
266 NEW => {
267 prev_actions => [ ], # Actions containing buttons
268 # leading to this status
269 id => 'NEW', # ID of this status
270 name => 'New request', # UI name of this status
271 ui_method_name => 'New request', # UI name of method leading
272 # to this status
273 method => 'create', # method to this status
274 next_actions => [ 'REQ', 'GENREQ', 'KILL' ], # buttons to add to all
275 # requests with this status
276 ui_method_icon => 'fa-plus', # UI Style class
278 REQ => {
279 prev_actions => [ 'NEW', 'REQREV', 'QUEUED', 'CANCREQ' ],
280 id => 'REQ',
281 name => 'Requested',
282 ui_method_name => 'Confirm request',
283 method => 'confirm',
284 next_actions => [ 'REQREV', 'COMP' ],
285 ui_method_icon => 'fa-check',
287 GENREQ => {
288 prev_actions => [ 'NEW', 'REQREV' ],
289 id => 'GENREQ',
290 name => 'Requested from partners',
291 ui_method_name => 'Place request with partners',
292 method => 'generic_confirm',
293 next_actions => [ 'COMP' ],
294 ui_method_icon => 'fa-send-o',
296 REQREV => {
297 prev_actions => [ 'REQ' ],
298 id => 'REQREV',
299 name => 'Request reverted',
300 ui_method_name => 'Revert Request',
301 method => 'cancel',
302 next_actions => [ 'REQ', 'GENREQ', 'KILL' ],
303 ui_method_icon => 'fa-times',
305 QUEUED => {
306 prev_actions => [ ],
307 id => 'QUEUED',
308 name => 'Queued request',
309 ui_method_name => 0,
310 method => 0,
311 next_actions => [ 'REQ', 'KILL' ],
312 ui_method_icon => 0,
314 CANCREQ => {
315 prev_actions => [ 'NEW' ],
316 id => 'CANCREQ',
317 name => 'Cancellation requested',
318 ui_method_name => 0,
319 method => 0,
320 next_actions => [ 'KILL', 'REQ' ],
321 ui_method_icon => 0,
323 COMP => {
324 prev_actions => [ 'REQ' ],
325 id => 'COMP',
326 name => 'Completed',
327 ui_method_name => 'Mark completed',
328 method => 'mark_completed',
329 next_actions => [ ],
330 ui_method_icon => 'fa-check',
332 KILL => {
333 prev_actions => [ 'QUEUED', 'REQREV', 'NEW', 'CANCREQ' ],
334 id => 'KILL',
335 name => 0,
336 ui_method_name => 'Delete request',
337 method => 'delete',
338 next_actions => [ ],
339 ui_method_icon => 'fa-trash',
344 =head3 _core_status_graph
346 my $status_graph = $illrequest->_core_status_graph($origin, $new_graph);
348 Return a new status_graph, the result of merging $origin & new_graph. This is
349 operation is a union over the sets defied by the two graphs.
351 Each entry in $new_graph is added to $origin. We do not provide a syntax for
352 'subtraction' of entries from $origin.
354 Whilst it is not intended that this works, you can override entries in $origin
355 with entries with the same key in $new_graph. This can lead to problematic
356 behaviour when $new_graph adds an entry, which modifies a dependent entry in
357 $origin, only for the entry in $origin to be replaced later with a new entry
358 from $new_graph.
360 NOTE: this procedure does not "re-link" entries in $origin or $new_graph,
361 i.e. each of the graphs need to be correct at the outset of the operation.
363 =cut
365 sub _status_graph_union {
366 my ( $self, $core_status_graph, $backend_status_graph ) = @_;
367 # Create new status graph with:
368 # - all core_status_graph
369 # - for-each each backend_status_graph
370 # + add to new status graph
371 # + for each core prev_action:
372 # * locate core_status
373 # * update next_actions with additional next action.
374 # + for each core next_action:
375 # * locate core_status
376 # * update prev_actions with additional prev action
378 my @core_status_ids = keys %{$core_status_graph};
379 my $status_graph = clone($core_status_graph);
381 foreach my $backend_status_key ( keys %{$backend_status_graph} ) {
382 my $backend_status = $backend_status_graph->{$backend_status_key};
383 # Add to new status graph
384 $status_graph->{$backend_status_key} = $backend_status;
385 # Update all core methods' next_actions.
386 foreach my $prev_action ( @{$backend_status->{prev_actions}} ) {
387 if ( grep $prev_action, @core_status_ids ) {
388 my @next_actions =
389 @{$status_graph->{$prev_action}->{next_actions}};
390 push @next_actions, $backend_status_key;
391 $status_graph->{$prev_action}->{next_actions}
392 = \@next_actions;
395 # Update all core methods' prev_actions
396 foreach my $next_action ( @{$backend_status->{next_actions}} ) {
397 if ( grep $next_action, @core_status_ids ) {
398 my @prev_actions =
399 @{$status_graph->{$next_action}->{prev_actions}};
400 push @prev_actions, $backend_status_key;
401 $status_graph->{$next_action}->{prev_actions}
402 = \@prev_actions;
407 return $status_graph;
410 ### Core API methods
412 =head3 capabilities
414 my $capabilities = $illrequest->capabilities;
416 Return a hashref mapping methods to operation names supported by the queried
417 backend.
419 Example return value:
421 { create => "Create Request", confirm => "Progress Request" }
423 NOTE: this module suffers from a confusion in termninology:
425 in _backend_capability, the notion of capability refers to an optional feature
426 that is implemented in core, but might not be supported by a given backend.
428 in capabilities & custom_capability, capability refers to entries in the
429 status_graph (after union between backend and core).
431 The easiest way to fix this would be to fix the terminology in
432 capabilities & custom_capability and their callers.
434 =cut
436 sub capabilities {
437 my ( $self, $status ) = @_;
438 # Generate up to date status_graph
439 my $status_graph = $self->_status_graph_union(
440 $self->_core_status_graph,
441 $self->_backend->status_graph({
442 request => $self,
443 other => {}
446 # Extract available actions from graph.
447 return $status_graph->{$status} if $status;
448 # Or return entire graph.
449 return $status_graph;
452 =head3 custom_capability
454 Return the result of invoking $CANDIDATE on this request's backend with
455 $PARAMS, or 0 if $CANDIDATE is an unknown method on backend.
457 NOTE: this module suffers from a confusion in termninology:
459 in _backend_capability, the notion of capability refers to an optional feature
460 that is implemented in core, but might not be supported by a given backend.
462 in capabilities & custom_capability, capability refers to entries in the
463 status_graph (after union between backend and core).
465 The easiest way to fix this would be to fix the terminology in
466 capabilities & custom_capability and their callers.
468 =cut
470 sub custom_capability {
471 my ( $self, $candidate, $params ) = @_;
472 foreach my $capability ( values %{$self->capabilities} ) {
473 if ( $candidate eq $capability->{method} ) {
474 my $response =
475 $self->_backend->$candidate({
476 request => $self,
477 other => $params,
479 return $self->expandTemplate($response);
482 return 0;
485 =head3 available_backends
487 Return a list of available backends.
489 =cut
491 sub available_backends {
492 my ( $self ) = @_;
493 my $backends = $self->_config->available_backends;
494 return $backends;
497 =head3 available_actions
499 Return a list of available actions.
501 =cut
503 sub available_actions {
504 my ( $self ) = @_;
505 my $current_action = $self->capabilities($self->status);
506 my @available_actions = map { $self->capabilities($_) }
507 @{$current_action->{next_actions}};
508 return \@available_actions;
511 =head3 mark_completed
513 Mark a request as completed (status = COMP).
515 =cut
517 sub mark_completed {
518 my ( $self ) = @_;
519 $self->status('COMP')->store;
520 return {
521 error => 0,
522 status => '',
523 message => '',
524 method => 'mark_completed',
525 stage => 'commit',
526 next => 'illview',
530 =head2 backend_migrate
532 Migrate a request from one backend to another.
534 =cut
536 sub backend_migrate {
537 my ( $self, $params ) = @_;
539 my $response = $self->_backend_capability('migrate',{
540 request => $self,
541 other => $params,
543 return $self->expandTemplate($response) if $response;
544 return $response;
547 =head2 backend_confirm
549 Confirm a request. The backend handles setting of mandatory fields in the commit stage:
551 =over
553 =item * orderid
555 =item * accessurl, cost (if available).
557 =back
559 =cut
561 sub backend_confirm {
562 my ( $self, $params ) = @_;
564 my $response = $self->_backend->confirm({
565 request => $self,
566 other => $params,
568 return $self->expandTemplate($response);
571 =head3 backend_update_status
573 =cut
575 sub backend_update_status {
576 my ( $self, $params ) = @_;
577 return $self->expandTemplate($self->_backend->update_status($params));
580 =head3 backend_cancel
582 my $ILLResponse = $illRequest->backend_cancel;
584 The standard interface method allowing for request cancellation.
586 =cut
588 sub backend_cancel {
589 my ( $self, $params ) = @_;
591 my $result = $self->_backend->cancel({
592 request => $self,
593 other => $params
596 return $self->expandTemplate($result);
599 =head3 backend_renew
601 my $renew_response = $illRequest->backend_renew;
603 The standard interface method allowing for request renewal queries.
605 =cut
607 sub backend_renew {
608 my ( $self ) = @_;
609 return $self->expandTemplate(
610 $self->_backend->renew({
611 request => $self,
616 =head3 backend_create
618 my $create_response = $abstractILL->backend_create($params);
620 Return an array of Record objects created by querying our backend with
621 a Search query.
623 In the context of the other ILL methods, this is a special method: we only
624 pass it $params, as it does not yet have any other data associated with it.
626 =cut
628 sub backend_create {
629 my ( $self, $params ) = @_;
631 # Establish whether we need to do a generic copyright clearance.
632 if ($params->{opac}) {
633 if ( ( !$params->{stage} || $params->{stage} eq 'init' )
634 && C4::Context->preference("ILLModuleCopyrightClearance") ) {
635 return {
636 error => 0,
637 status => '',
638 message => '',
639 method => 'create',
640 stage => 'copyrightclearance',
641 value => {
642 backend => $self->_backend->name
645 } elsif ( defined $params->{stage}
646 && $params->{stage} eq 'copyrightclearance' ) {
647 $params->{stage} = 'init';
650 # First perform API action, then...
651 my $args = {
652 request => $self,
653 other => $params,
655 my $result = $self->_backend->create($args);
657 # ... simple case: we're not at 'commit' stage.
658 my $stage = $result->{stage};
659 return $self->expandTemplate($result)
660 unless ( 'commit' eq $stage );
662 # ... complex case: commit!
664 # Do we still have space for an ILL or should we queue?
665 my $permitted = $self->check_limits(
666 { patron => $self->patron }, { librarycode => $self->branchcode }
669 # Now augment our committed request.
671 $result->{permitted} = $permitted; # Queue request?
673 # This involves...
675 # ...Updating status!
676 $self->status('QUEUED')->store unless ( $permitted );
678 return $self->expandTemplate($result);
681 =head3 expandTemplate
683 my $params = $abstract->expandTemplate($params);
685 Return a version of $PARAMS augmented with our required template path.
687 =cut
689 sub expandTemplate {
690 my ( $self, $params ) = @_;
691 my $backend = $self->_backend->name;
692 # Generate path to file to load
693 my $backend_dir = $self->_config->backend_dir;
694 my $backend_tmpl = join "/", $backend_dir, $backend;
695 my $intra_tmpl = join "/", $backend_tmpl, "intra-includes",
696 $params->{method} . ".inc";
697 my $opac_tmpl = join "/", $backend_tmpl, "opac-includes",
698 $params->{method} . ".inc";
699 # Set files to load
700 $params->{template} = $intra_tmpl;
701 $params->{opac_template} = $opac_tmpl;
702 return $params;
705 #### Abstract Imports
707 =head3 getLimits
709 my $limit_rules = $abstract->getLimits( {
710 type => 'brw_cat' | 'branch',
711 value => $value
712 } );
714 Return the ILL limit rules for the supplied combination of type / value.
716 As the config may have no rules for this particular type / value combination,
717 or for the default, we must define fall-back values here.
719 =cut
721 sub getLimits {
722 my ( $self, $params ) = @_;
723 my $limits = $self->_config->getLimitRules($params->{type});
725 if ( defined $params->{value}
726 && defined $limits->{$params->{value}} ) {
727 return $limits->{$params->{value}};
729 else {
730 return $limits->{default} || { count => -1, method => 'active' };
734 =head3 getPrefix
736 my $prefix = $abstract->getPrefix( {
737 branch => $branch_code
738 } );
740 Return the ILL prefix as defined by our $params: either per borrower category,
741 per branch or the default.
743 =cut
745 sub getPrefix {
746 my ( $self, $params ) = @_;
747 my $brn_prefixes = $self->_config->getPrefixes();
748 return $brn_prefixes->{$params->{branch}} || ""; # "the empty prefix"
751 =head3 get_type
753 my $type = $abstract->get_type();
755 Return a string representing the material type of this request or undef
757 =cut
759 sub get_type {
760 my ($self) = @_;
761 my $attr = $self->illrequestattributes->find({ type => 'type'});
762 return if !$attr;
763 return $attr->value;
766 #### Illrequests Imports
768 =head3 check_limits
770 my $ok = $illRequests->check_limits( {
771 borrower => $borrower,
772 branchcode => 'branchcode' | undef,
773 } );
775 Given $PARAMS, a hashref containing a $borrower object and a $branchcode,
776 see whether we are still able to place ILLs.
778 LimitRules are derived from koha-conf.xml:
779 + default limit counts, and counting method
780 + branch specific limit counts & counting method
781 + borrower category specific limit counts & counting method
782 + err on the side of caution: a counting fail will cause fail, even if
783 the other counts passes.
785 =cut
787 sub check_limits {
788 my ( $self, $params ) = @_;
789 my $patron = $params->{patron};
790 my $branchcode = $params->{librarycode} || $patron->branchcode;
792 # Establish maximum number of allowed requests
793 my ( $branch_rules, $brw_rules ) = (
794 $self->getLimits( {
795 type => 'branch',
796 value => $branchcode
797 } ),
798 $self->getLimits( {
799 type => 'brw_cat',
800 value => $patron->categorycode,
801 } ),
803 my ( $branch_limit, $brw_limit )
804 = ( $branch_rules->{count}, $brw_rules->{count} );
805 # Establish currently existing requests
806 my ( $branch_count, $brw_count ) = (
807 $self->_limit_counter(
808 $branch_rules->{method}, { branchcode => $branchcode }
810 $self->_limit_counter(
811 $brw_rules->{method}, { borrowernumber => $patron->borrowernumber }
815 # Compare and return
816 # A limit of -1 means no limit exists.
817 # We return blocked if either branch limit or brw limit is reached.
818 if ( ( $branch_limit != -1 && $branch_limit <= $branch_count )
819 || ( $brw_limit != -1 && $brw_limit <= $brw_count ) ) {
820 return 0;
821 } else {
822 return 1;
826 sub _limit_counter {
827 my ( $self, $method, $target ) = @_;
829 # Establish parameters of counts
830 my $resultset;
831 if ($method && $method eq 'annual') {
832 $resultset = Koha::Illrequests->search({
833 -and => [
834 %{$target},
835 \"YEAR(placed) = YEAR(NOW())"
838 } else { # assume 'active'
839 # XXX: This status list is ugly. There should be a method in config
840 # to return these.
841 my $where = { status => { -not_in => [ 'QUEUED', 'COMP' ] } };
842 $resultset = Koha::Illrequests->search({ %{$target}, %{$where} });
845 # Fetch counts
846 return $resultset->count;
849 =head3 requires_moderation
851 my $status = $illRequest->requires_moderation;
853 Return the name of the status if moderation by staff is required; or 0
854 otherwise.
856 =cut
858 sub requires_moderation {
859 my ( $self ) = @_;
860 my $require_moderation = {
861 'CANCREQ' => 'CANCREQ',
863 return $require_moderation->{$self->status};
866 =head3 generic_confirm
868 my $stage_summary = $illRequest->generic_confirm;
870 Handle the generic_confirm extended method. The first stage involves creating
871 a template email for the end user to edit in the browser. The second stage
872 attempts to submit the email.
874 =cut
876 sub generic_confirm {
877 my ( $self, $params ) = @_;
878 my $branch = Koha::Libraries->find($params->{current_branchcode})
879 || die "Invalid current branchcode. Are you logged in as the database user?";
880 if ( !$params->{stage}|| $params->{stage} eq 'init' ) {
881 my $draft->{subject} = "ILL Request";
882 $draft->{body} = <<EOF;
883 Dear Sir/Madam,
885 We would like to request an interlibrary loan for a title matching the
886 following description:
890 my $details = $self->metadata;
891 while (my ($title, $value) = each %{$details}) {
892 $draft->{body} .= " - " . $title . ": " . $value . "\n"
893 if $value;
895 $draft->{body} .= <<EOF;
897 Please let us know if you are able to supply this to us.
899 Kind Regards
903 my @address = map { $branch->$_ }
904 qw/ branchname branchaddress1 branchaddress2 branchaddress3
905 branchzip branchcity branchstate branchcountry branchphone
906 branchemail /;
907 my $address = "";
908 foreach my $line ( @address ) {
909 $address .= $line . "\n" if $line;
912 $draft->{body} .= $address;
914 my $partners = Koha::Patrons->search({
915 categorycode => $self->_config->partner_code
917 return {
918 error => 0,
919 status => '',
920 message => '',
921 method => 'generic_confirm',
922 stage => 'draft',
923 value => {
924 draft => $draft,
925 partners => $partners,
929 } elsif ( 'draft' eq $params->{stage} ) {
930 # Create the to header
931 my $to = $params->{partners};
932 if ( defined $to ) {
933 $to =~ s/^\x00//; # Strip leading NULLs
934 $to =~ s/\x00/; /; # Replace others with '; '
936 Koha::Exceptions::Ill::NoTargetEmail->throw(
937 "No target email addresses found. Either select at least one partner or check your ILL partner library records.")
938 if ( !$to );
939 # Create the from, replyto and sender headers
940 my $from = $branch->branchemail;
941 my $replyto = $branch->branchreplyto || $from;
942 Koha::Exceptions::Ill::NoLibraryEmail->throw(
943 "Your library has no usable email address. Please set it.")
944 if ( !$from );
946 # Create the email
947 my $message = Koha::Email->new;
948 my %mail = $message->create_message_headers(
950 to => $to,
951 from => $from,
952 replyto => $replyto,
953 subject => Encode::encode( "utf8", $params->{subject} ),
954 message => Encode::encode( "utf8", $params->{body} ),
955 contenttype => 'text/plain',
958 # Send it
959 my $result = sendmail(%mail);
960 if ( $result ) {
961 $self->status("GENREQ")->store;
962 return {
963 error => 0,
964 status => '',
965 message => '',
966 method => 'generic_confirm',
967 stage => 'commit',
968 next => 'illview',
970 } else {
971 return {
972 error => 1,
973 status => 'email_failed',
974 message => $Mail::Sendmail::error,
975 method => 'generic_confirm',
976 stage => 'draft',
979 } else {
980 die "Unknown stage, should not have happened."
984 =head3 id_prefix
986 my $prefix = $record->id_prefix;
988 Return the prefix appropriate for the current Illrequest as derived from the
989 borrower and branch associated with this request's Status, and the config
990 file.
992 =cut
994 sub id_prefix {
995 my ( $self ) = @_;
996 my $prefix = $self->getPrefix( {
997 branch => $self->branchcode,
998 } );
999 $prefix .= "-" if ( $prefix );
1000 return $prefix;
1003 =head3 _censor
1005 my $params = $illRequest->_censor($params);
1007 Return $params, modified to reflect our censorship requirements.
1009 =cut
1011 sub _censor {
1012 my ( $self, $params ) = @_;
1013 my $censorship = $self->_config->censorship;
1014 $params->{censor_notes_staff} = $censorship->{censor_notes_staff}
1015 if ( $params->{opac} );
1016 $params->{display_reply_date} = ( $censorship->{censor_reply_date} ) ? 0 : 1;
1018 return $params;
1021 =head3 TO_JSON
1023 $json = $illrequest->TO_JSON
1025 Overloaded I<TO_JSON> method that takes care of inserting calculated values
1026 into the unblessed representation of the object.
1028 TODO: This method does nothing and is not called anywhere. However, bug 74325
1029 touches it, so keeping this for now until both this and bug 74325 are merged,
1030 at which point we can sort it out and remove it completely
1032 =cut
1034 sub TO_JSON {
1035 my ( $self, $embed ) = @_;
1037 my $object = $self->SUPER::TO_JSON();
1039 return $object;
1042 =head2 Internal methods
1044 =head3 _type
1046 =cut
1048 sub _type {
1049 return 'Illrequest';
1052 =head1 AUTHOR
1054 Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
1056 =cut