@@ -, +, @@ --- Koha/Illrequest.pm | 222 ++++++++++++++++++++- ill/ill-requests.pl | 8 + .../intranet-tmpl/prog/css/src/staff-global.scss | 4 + .../prog/en/modules/ill/ill-requests.tt | 163 +++++++++++++++ 4 files changed, 394 insertions(+), 3 deletions(-) --- a/Koha/Illrequest.pm +++ a/Koha/Illrequest.pm @@ -36,6 +36,12 @@ use Koha::AuthorisedValue; use Koha::Illrequest::Logger; use Koha::Patron; use Koha::AuthorisedValues; +use Koha::Biblios; +use Koha::Items; +use Koha::ItemTypes; +use Koha::Libraries; +use C4::Items qw( AddItem ); +use C4::Circulation qw( CanBookBeIssued AddIssue ); use base qw(Koha::Object); @@ -426,7 +432,7 @@ sub _core_status_graph { name => 'Requested', ui_method_name => 'Confirm request', method => 'confirm', - next_actions => [ 'REQREV', 'COMP' ], + next_actions => [ 'REQREV', 'COMP', 'CHK' ], ui_method_icon => 'fa-check', }, GENREQ => { @@ -435,7 +441,7 @@ sub _core_status_graph { name => 'Requested from partners', ui_method_name => 'Place request with partners', method => 'generic_confirm', - next_actions => [ 'COMP' ], + next_actions => [ 'COMP', 'CHK' ], ui_method_icon => 'fa-send-o', }, REQREV => { @@ -471,7 +477,7 @@ sub _core_status_graph { name => 'Completed', ui_method_name => 'Mark completed', method => 'mark_completed', - next_actions => [ ], + next_actions => [ 'CHK' ], ui_method_icon => 'fa-check', }, KILL => { @@ -483,6 +489,15 @@ sub _core_status_graph { next_actions => [ ], ui_method_icon => 'fa-trash', }, + CHK => { + prev_actions => [ 'REQ', 'GENREQ', 'COMP' ], + id => 'CHK', + name => 'Checked out', + ui_method_name => 'Check out', + method => 'check_out', + next_actions => [ ], + ui_method_icon => 'fa-upload', + } }; } @@ -1024,6 +1039,207 @@ sub requires_moderation { return $require_moderation->{$self->status}; } +=head3 check_out + + my $stage_summary = $request->check_out; + +Handle the check_out method. The first stage involves gathering the required +data from the user via a form, the second stage creates an item and tries to +issue it to the patron. If successful, it notifies the patron, then it +returns a summary of how things went + +=cut + +sub check_out { + my ( $self, $params ) = @_; + + # Objects required by the template + my $itemtypes = Koha::ItemTypes->search( + {}, + { order_by => ['description'] } + ); + my $libraries = Koha::Libraries->search( + {}, + { order_by => ['branchcode'] } + ); + my $biblio = Koha::Biblios->find({ + biblionumber => $self->biblio_id + }); + # Find all statistical patrons + my $statistical_patrons = Koha::Patrons->search( + { 'category_type' => 'x' }, + { join => { 'categorycode' => 'borrowers' } } + ); + + if (!$params->{stage} || $params->{stage} eq 'init') { + # Present a form to gather the required data + # + # We may be viewing this page having previously tried to issue + # the item (in which case, we may already have created an item) + # so we pass the biblio for this request + return { + method => 'check_out', + stage => 'form', + value => { + itemtypes => $itemtypes, + libraries => $libraries, + statistical => $statistical_patrons, + biblio => $biblio + } + }; + } elsif ($params->{stage} eq 'form') { + # Validate what we've got and return with an error if we fail + my $errors = {}; + if (!$params->{item_type} || length $params->{item_type} == 0) { + $errors->{item_type} = 1; + } + if ($params->{inhouse} && length $params->{inhouse} > 0) { + my $patron_count = Koha::Patrons->search({ + cardnumber => $params->{inhouse} + })->count(); + if ($patron_count != 1) { + $errors->{inhouse} = 1; + } + } + + # Check we don't have more than one item for this bib, + # if we do, something very odd is going on + # Having 1 is OK, it means we're likely trying to issue + # following a previously failed attempt, the item exists + # so we'll use it + my @items = $biblio->items->as_list; + my $item_count = scalar @items; + if ($item_count > 1) { + $errors->{itemcount} = 1; + } + + # Failed validation, go back to the form + if (%{$errors}) { + return { + method => 'check_out', + stage => 'form', + value => { + params => $params, + statistical => $statistical_patrons, + itemtypes => $itemtypes, + libraries => $libraries, + biblio => $biblio, + errors => $errors + } + }; + } + + # Passed validation + # + # Create an item if one doesn't already exist, + # if one does, use that + my $itemnumber; + if ($item_count == 0) { + my $item_hash = { + homebranch => $params->{branchcode}, + holdingbranch => $params->{branchcode}, + location => $params->{branchcode}, + itype => $params->{item_type}, + barcode => 'ILL-' . $self->illrequest_id + }; + my (undef, undef, $item_no) = + AddItem($item_hash, $self->biblio_id); + $itemnumber = $item_no; + } else { + $itemnumber = $items[0]->itemnumber; + } + # Check we have an item before going forward + if (!$itemnumber) { + return { + method => 'check_out', + stage => 'form', + value => { + params => $params, + itemtypes => $itemtypes, + libraries => $libraries, + statistical => $statistical_patrons, + errors => { item_creation => 1 } + } + }; + } + + # Do the check out + # + # Gather what we need + my $target_item = Koha::Items->find( $itemnumber ); + # Determine who we're issuing to + my $patron = $params->{inhouse} && length $params->{inhouse} > 0 ? + Koha::Patrons->find({ cardnumber => $params->{inhouse} }) : + $self->patron; + + my @issue_args = ( + $patron, + scalar $target_item->barcode + ); + if ($params->{duedate} && length $params->{duedate} > 0) { + push @issue_args, $params->{duedate}; + } + # Check if we can check out + my ( $error, $confirm, $alerts, $messages ) = + C4::Circulation::CanBookBeIssued(@issue_args); + + # If we got anything back saying we can't check out, + # return it to the template + my $problems = {}; + if ( $error && %{$error} ) { $problems->{error} = $error }; + if ( $confirm && %{$confirm} ) { $problems->{confirm} = $confirm }; + if ( $alerts && %{$alerts} ) { $problems->{alerts} = $alerts }; + if ( $messages && %{$messages} ) { $problems->{messages} = $messages }; + + if (%{$problems}) { + return { + method => 'check_out', + stage => 'form', + value => { + params => $params, + itemtypes => $itemtypes, + libraries => $libraries, + statistical => $statistical_patrons, + patron => $patron, + biblio => $biblio, + check_out_errors => $problems + } + }; + } + + # We can allegedly check out, so make it so + # For some reason, AddIssue requires an unblessed Patron + $issue_args[0] = $patron->unblessed; + my $issue = C4::Circulation::AddIssue(@issue_args); + + if ($issue && %{$issue}) { + # Update the request status + $self->status('CHK')->store; + return { + method => 'check_out', + stage => 'done_check_out', + value => { + params => $params, + patron => $patron, + check_out => $issue + } + }; + } else { + return { + method => 'check_out', + stage => 'form', + value => { + params => $params, + itemtypes => $itemtypes, + libraries => $libraries, + errors => { item_check_out => 1 } + } + }; + } + } + +} + =head3 generic_confirm my $stage_summary = $illRequest->generic_confirm; --- a/ill/ill-requests.pl +++ a/ill/ill-requests.pl @@ -267,6 +267,14 @@ if ( $backends_available ) { # handle special commit rules & update type handle_commit_maybe($backend_result, $request); + } elsif ( $op eq 'check_out') { + my $request = Koha::Illrequests->find($params->{illrequest_id}); + my $backend_result = $request->check_out($params); + $template->param( + params => $params, + whole => $backend_result, + request => $request + ); } elsif ( $op eq 'illlist') { # If we receive a pre-filter, make it available to the template --- a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss +++ a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss @@ -3961,6 +3961,10 @@ input.renew { width: 100% !important; } +#ill-issue-title { + margin: 20px 0 30px 0; +} + #stockrotation { h3 { margin: 30px 0 10px 0; --- a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/ill/ill-requests.tt @@ -111,6 +111,152 @@

Cancel a confirmed request

[% PROCESS $whole.template %] + [% ELSIF query_type == 'check_out' and !whole.error %] + [% IF !whole.stage || whole.stage == 'form' %] +

Issue requested item to [% request.patron.firstname %] [% request.patron.surname %]

+ [% IF !request.biblio_id || request.biblio_id.length == 0 %] +
This item cannot be issued as it has no biblio record associated with it
+ [% END %] + [% IF whole.value.errors.itemcount %] +
The bibliographic record for this request has multiple items, it should only have one. Please fix this then try again.
+ [% END %] + [% IF whole.value.errors.item_creation %] +
An unknown error occurred while trying to add an item
+ [% END %] + [% IF whole.value.errors.item_check_out %] +
An unknown error occurred while trying to check out the item
+ [% END %] + [% IF whole.value.check_out_errors %] + [% IF whole.value.check_out_errors.error.STATS %] +
+ Local use recorded +
+ [% ELSE %] +
+ There was a problem checking this item out, please check for problems with the patron's account +
+ [% END %] + [% END %] + [% IF request.biblio_id && request.biblio_id.length > 0 && !whole.value.check_out_errors.error.STATS %] +
+
+ Check out details + [% items = whole.value.biblio.items.unblessed %] + [% IF items.size == 1 %] +

The bibliographic record for this request already has an item attached to it, you are about to check it out

+ [% ELSE %] +

A bibliographic record for this request exists, but no item. You are about to create an item and check it out

+ [% END %] +
    +
  1. + + + [% IF whole.value.errors.inhouse %] + You must choose a valid patron + [% END %] +
    If you do not wish to check out the item to [% request.patron.firstname | html %] [% request.patron.surname | html %] and would rather issue it to an in-house statistical patron, choose the patron here
    +
  2. +
  3. + + [% IF items.size != 1 %] + + [% ELSE %] + [% FOREACH type IN whole.value.itemtypes %] + [% IF type.itemtype == items.0.itype %] + [% type.description | html %] + [% END %] + [% END %] + [% END %] + [% IF whole.value.errors.item_type %] + You must choose an item type + [% END %] +
  4. + [% IF items.size == 1 %] +
  5. + + [% items.0.barcode %] +
  6. + [% END %] +
  7. + + [% branchcode = items.size == 1 ? items.0.homebranch : params.branchcode ? params.branchcode : request.branchcode %] + [% IF items.size != 1 %] + + [% ELSE %] + [% FOREACH branch IN whole.value.libraries.unblessed %] + [% IF branch.branchcode == branchcode %] + [% branch.branchname %] + [% END %] + [% END %] + [% END %] + [% IF whole.value.errors.branchcode %] + You must choose a branch + [% END %] +
  8. +
  9. + + [% INCLUDE 'date-format.inc' %] +
    If you do not specify a due date, it will be set according to circulation rules

    +
  10. +
+
+
+ + + [% IF items.size == 1 %] + + + [% END %] + + + Cancel +
+
+ [% END %] + [% IF whole.value.check_out_errors.error.STATS %] + Return to request + [% END %] + [% ELSIF whole.stage == 'done_check_out' %] +

Item checked out

+
+ Check out details +
    +
  1. + + [% whole.value.patron.firstname | html %] [% whole.value.patron.surname | html %] +
  2. +
  3. + + [% whole.value.check_out.date_due | $KohaDates with_hours => 1 %] +
  4. +
+
+
+ Return to request +
+ [% END %] + [% ELSIF query_type == 'generic_confirm' %]

Place request with partner libraries

[% IF error %] @@ -534,14 +680,31 @@ [% INCLUDE 'datatables.inc' %] [% INCLUDE 'columns_settings.inc' %] [% INCLUDE 'calendar.inc' %] + [% Asset.js("lib/jquery/plugins/jquery-ui-timepicker-addon.min.js") | $raw %] [% Asset.js("lib/jquery/plugins/jquery.checkboxes.min.js") | $raw %] + [% INCLUDE 'ill-list-table-strings.inc' %] [% Asset.js("js/ill-list-table.js") | $raw %] + [% Asset.js("js/ill-check-out.js") | $raw %] [% END %] [% TRY %] --