Bugzilla – Attachment 118274 Details for
Bug 19532
Recalls for Koha
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 19532: Recalls on intranet
Bug-19532-Recalls-on-intranet.patch (text/plain), 150.48 KB, created by
Aleisha Amohia
on 2021-03-16 02:19:49 UTC
(
hide
)
Description:
Bug 19532: Recalls on intranet
Filename:
MIME Type:
Creator:
Aleisha Amohia
Created:
2021-03-16 02:19:49 UTC
Size:
150.48 KB
patch
obsolete
>From 176bb09a756f2df88da01fa49730fe720374cf88 Mon Sep 17 00:00:00 2001 >From: Aleisha Amohia <aleishaamohia@hotmail.com> >Date: Mon, 11 May 2020 23:52:09 +0000 >Subject: [PATCH] Bug 19532: Recalls on intranet > >See recalls on Intranet >- old recalls (all inactive recalls) >- recalls queue (all active recalls) - cancel, expire, revert waiting status, multiple cancel, mark overdue >- recalls to pull (available but not yet waiting) - cancel >- recalls awaiting pickup (awaiting pickup, awaiting pickup more than RecallMaxPickUpDelay days) - expire, revert waiting status >- overdue recalls (overdue to be returned) - cancel, multiple cancel >- biblio recalls tab (all active recalls relevant to this bib) - cancel, expire, revert waiting status, mark overdue >- patron recalls tab (all active recalls relevant to this patron) - cancel, expire, revert waiting status, mark overdue >- patron recalls history tab (all recalls relevant to this patron) - cancel, expire, revert waiting status, mark overdue >- log viewer > >and the general circulation of recalls > >== TEST PLAN FOR RECALLS == > >ADMINISTRATION > >1. Apply all patches >2. Run database updates, update schema files and confirm everything applies cleanly >3. Run tests and confirm everything passes: >t/db_dependent/Koha/Recall.t >t/db_dependent/Koha/Recalls.t >t/db_dependent/Stats.t >t/db_dependent/Circulation/CalcFine.t >t/db_dependent/Koha/Item.t >t/db_dependent/Koha/Biblio.t >t/db_dependent/Koha/Patron.t >t/db_dependent/XSLT.t >t/db_dependent/Search.t >t/db_dependent/Holds.t >t/db_dependent/Circulation/transferbook.t >t/db_dependent/Circulation.t > >4. Go to Administration -> system preferences. Find the UseRecalls system preference. It should be DISABLED. Confirm RecallsMaxPickUpDelay is set to 7 by default. >5. Go to Administration -> circulation rules. Confirm there are no recalls circulation rules showing. >6. Test a few circulation flows: checking out, placing a reserve, checking in, fulfilling a reserve, etc. Confirm everything works as normal. > >7. Go to Administration -> system preferences. Enable the UseRecalls system preference. >8. Go to Administration -> circulation rules. Set the following rules: >Recalls allowed (count) = 0 >Recalls per record (count) = 0 >On shelf recalls allowed ( If any unavailable / If all unavailable ) = If any unavailable >Recall due date interval (days) = 3 >Recall overdue fine amount = (something different to your normal fine amount) >Recall pickup period (days) = 1 > >Throughout your testing, try with different combinations of these rules and itemtype / branchcode / categorycode. Also try with null values. Keep the circulation rules open in another tab so you can refer to and update these easily. You should also have at least one other tab open for the staff client, and a third tab open for the OPAC, for ease of testing. > >9. Go to your account -> More -> Set permissions. Confirm the recalls permission is checked. >10. Set up a test user with OPAC login details (Borrower A). This could also be your own user, as long as you have OPAC login access. >11. Set up a test record (Biblio A) with at least two items (Item A and Item B) of the same item type (or an item type with the same recall circ rules). > >PLACING A RECALL > >12. Log in to the OPAC as Borrower A. Do a catalogue search with a term that will return multiple results, including Biblio A. >13. Click on Biblio A. >14. Notice there is a 'Place recall' button on the sidebar menu. Click this button. There will be a message saying that there are no items to recall - this is because all items are available. > >15. Check out Item A to another borrower (Borrower B). >16. Refresh the 'Place recall' page. You will still NOT be able to place a recall - this is because Recalls allowed = 0 and Recalls per record = 0. > >17. Edit the circulation rules to have the following values: >Recalls allowed (count) = 1 >Recalls per record (count) = 1 >18. Refresh the 'Place recall' page. You will now see the form to place a recall. > >BIBLIO-LEVEL RECALL, NO TRANSFER > >19. Place a biblio-level recall. >Pickup location: Branch A, the set branch when you are logged into the staff client >Recall not needed after (expiration date): whatever you want >Select 'recall next available item' >Click confirm >20. Confirm the recall is placed successfully. Confirm that the new due date displayed is correctly calculated to be today's date, plus 3 days (taken from the 'recall due date interval' circ rule) >21. In the staff client, look at Borrower B's account, and go to their Notices tab. Confirm they have received a 'Notification to return recalled item' notice. >22. Look at Borrower B's checkouts table. Notice the due date for their checkout has been adjusted, and there is now a note to say that the item was recalled and the due date adjusted. >23. Log in to the OPAC as Borrower B and go to your summary tab. Notice there is a note under their checkout to say the item had been recalled. > >24. Log out of the OPAC and log back in as Borrower A. >25. Go to your summary tab. Confirm there is a Recalls tab with a count of 1. >26. Cancel the recall using the button. Confirm it cancels and the Recalls tab disappears. > >27. Do a catalogue search with a term that will return multiple results, including Biblio A. >28. When the results load, notice there is a 'Place recall' button next to the 'Place hold' button. Click this 'Place recall' button. >29. Notice you are redirected straight to the form to place a recall. >30. Place a biblio-level recall again, following the steps in Step 19. > >31. Go to your recalls history tab. Notice your first cancelled recall shows here. >32. Cancel the recall you just created, using the button. Confirm it cancels and you are redirected to your summary tab. > >33. In the staff client, enable the UseCourseReserves system preference. >34. Go to the main menu, click Course Reserves. >35. Add a new course. (You may also have to define an authorised value for DEPARTMENT.) >36. Add Item A as a reserve to this course. > >37. View Course Reserves in the OPAC. Click the course you just created. >38. Notice the reserve has a Recall button underneath it's 'Checked out' status. Click this button. >39. Place a biblio-level recall again, following the steps in Step 19. > >40. Click the 'Place recall' link in the breadcrumbs. >41. Notice there is a message saying that you have reached the max number of recalls on this record. This is because Recalls allowed = 1 and Recalls per record = 1. >42. Edit the circulation rules to have the following values: >Recalls allowed (count) = 10 >Recalls per record (count) = 5 >43. Refresh the 'Place recall' page. You will now see the form to place a recall. > >44. Create another test record (Biblio B) with at least one item (Item C). >45. Find this record on the OPAC and place a biblio-level recall again, following the steps in Step 19. > >46. In the staff client, go to Circulation -> Old recalls. You should be able to see your two cancelled recalls. >47. Go to Circulation -> Recalls queue. Your current recalls should show here. >48. Use the 'Select all' checkbox to select all recalls. >49. Cancel the recalls using the 'Cancel selected recalls' button. > >50. Go to the OPAC and place a biblio-level recall on Biblio A again, following the steps in Step 19. > >51. In the staff client, check in Item A, which should still be checked out to Borrower B. >52. A box should pop-up asking you to confirm Borrower A's recall. Click ignore. >53. Click the link to go view Biblio A's details in the catalogue. >54. Click the recalls tab. Notice Borrower A's recall is displayed, and shows it is still Requested (has not been confirmed waiting). > >55. Check in Item A again. This time, confirm the recall as waiting using the "Confirm recall" button. >56. Go to Borrower A's Notices tab. Confirm there is a notice "Recalled item awaiting pickup". >57. Go to Borrower A's checkouts. Notice there is a recalls tab. Confirm the recall is showing as "Ready for pickup". >58. Click the 'Actions' dropdown. Click the "Revert waiting" button. The page should show a message that the waiting status has been reverted, without reloading. > >59. This time, check in Item B. The recall confirmation box should show again, because this a biblio-level recall that any recallable item under Biblio A can fill. Click the "Print slip and confirm" button. >60. Check the slip that is generated. Confirm it contains Borrower A's correct details, and the details of the recall are correct. >61. Go to Circulation -> Recalls awaiting pickup. Confirm the recall is now waiting and shows in this list. >(You could also try this with Item B having a different item type to Item A, and circ rules not allowing Item B's item type to have recalls. When checking in Item A, it should not trigger the recall box). > >62. Go to Borrower A's checkouts. Check out Item B. >63. Confirm the checkout is successful and the recall is removed from the Recalls tab. >64. Go to Circulation -> Old recalls. The fulfilled recall should show. > >65. Check in Item B. > >BIBLIO-LEVEL RECALL, TRANSFER REQUIRED > >66. Check out Item A to Borrower B. >67. Log in to the OPAC as Borrower A. >68. Find Biblio A and place a biblio-level recall. >Pickup location: Branch B, a different branch from your logged in branch. This recall will require a transfer. >Recall not needed after (expiration date): whatever you want >Select 'recall next available item' >Click confirm > >69. In the staff client, check in Item A at Branch A. Notice the box that pops up shows that a transfer is required. >70. Click "confirm recall and transfer" and confirm the transfer. >71. Go to your account and click the Recalls tab. >72. Confirm the recall status now shows the item is in transit to Branch B. >73. In the drop-down top-right of your window, select 'Set library'. >74. Set your library to Branch B. > >75. Go to Circulation -> Transfers to receive. Notice that the recall is showing here. >76. Click 'Cancel transfer'. >77. Go to Circulation -> Recalls queue >78. Confirm the recall status has been reverted to Requested. > >79. Set your library back to Branch A. >80. Check in Item A and trigger the transfer. >81. Set your library back to Branch B. > >82. Check in Item A at Branch B. >83. When the 'Recall found' box pops up, click Ignore. >84. Go to Circulation -> Recalls to pull. The recall should show here, with a button to "Cancel recall and return to: Branch A" >85. Click the button to cancel the recall. > >86. Repeat Steps 66-70. >87. Check in Item A at Branch B. Confirm the recall as waiting. >88. Check out Item A to Borrower A to fulfill the recall. > >89. Set your library back to Branch A and check in Item A. > >ITEM-LEVEL RECALL, NO TRANSFER > >90. Go to Administration -> circulation rules. Set the following rules: >On shelf recalls allowed ( If any unavailable / If all unavailable ) = If all unavailable > >91. Check out Item A to Borrower B. >92. Log in to the OPAC as Borrower A and go to Biblio A. >93. Click the 'Place recall' button. Confirm there is a message that there are no items to recall. This is because On shelf recalls allowed = If all unavailable, and there is still one item (Item B) available. >94. In the staff client, edit Item B to have a withdrawn, item lost or not for loan status. >95. Refresh the 'Place recall' page. Confirm you can now see the form to place a recall. > >96. Place an item-level recall. >Pickup location: Branch A. >Recall not needed after (expiration date): whatever you want >Select 'recall a specific item' >Item B will not be selectable, and Item A should be selected by default. >Click confirm > >97. In the staff client, edit Item B and remove the lost or missing status. >98. Check in Item B. Confirm the recall box does not pop up, because it cannot fill the item-level recall. >99. Check in Item A. Confirm the recall as waiting. >100. Go to Circulation -> Recalls awaiting pickup >101. Expire the recall. Confirm it expires as expected. > >ITEM-LEVEL RECALL, TRANSFER REQUIRED > >102. Repeat steps 91 to 95. >103. Place an item-level recall. >Pickup location: Branch B, we will require a transfer. >Recall not needed after (expiration date): whatever you want >Select 'recall a specific item' >Item B will not be selectable, and Item A should be selected by default. >Click confirm >104. In the staff client, check in Item A. Confirm the recall and trigger the transfer. >105. Set your library to Branch B and check in Item A. >106. Confirm the recall as waiting. >107. Check out Item A to Borrower A and fulfill the recall. > >108. Set your library back to Branch A and check in Item A. > >CRONJOBS: EXPIRING RECALL > >109. Check out Item A to Borrower B. >110. Log in to the OPAC as Borrower A. Place a recall (any level) on Biblio A. >111. In your terminal, enter mysql and edit the expiration date of your recall to be before today >UPDATE recalls SET expirationdate = NOW()-2 WHERE recall_id = X; >112. Run the expiry cronjob from within your shell >perl misc/cronjobs/recalls/expire_recalls.pl >113. Go to Borrower A's account and go to the Recalls history tab >114. Confirm the recall has been expired because the current date surpassed the specified expiration date > >115. Check out Item A to Borrower B. >116. Log in to the OPAC as Borrower A. Place a recall (any level) on Biblio A. >117. In the staff client, check in Item A and confirm the recall as waiting. >118. In your terminal, enter mysql and edit the waiting date of your recall to be before today >UPDATE recalls SET waitingdate = NOW() - interval 5 day WHERE recall_id = X; >119. Run the expiry cronjob from within your shell >perl misc/cronjobs/recalls/expire_recalls.pl >120. Go to Borrower A's account and go to the Recalls history tab >121. Confirm the recall has been expired because the recall had been waiting for more days than the Recall pickup period > >122. Go to Administration -> circulation rules. Set the following rules: >Recall pickup period (days) = 0 >123. Set the RecallsMaxPickUpDelay system preference = 1. >124. Check out Item A to Borrower B. >125. Log in to the OPAC as Borrower A. Place a recall (any level) on Biblio A. >126. In the staff client, check in Item A and confirm the recall as waiting. >127. In your terminal, enter mysql and edit the waiting date of your recall to be before today >UPDATE recalls SET waitingdate = NOW()-2 WHERE recall_id = X; >128. Run the expiry cronjob from within your shell >perl misc/cronjobs/recalls/expire_recalls.pl >129. Go to Borrower A's account and go to the Recalls history tab >130. Confirm the recall has been expired because the recall had been waiting for more days than the RecallsMaxPickUpDelay syspref > >CRONJOBS: OVERDUE RECALL > >131. Check out Item A to Borrower B >132. Log in to the OPAC as Borrower A. Place a recall (any level) on Biblio A. >133. In your terminal, enter mysql and edit the due date of the checkout to Borrower B to be before today >UPDATE issues SET date_due = NOW()-2 WHERE issue_id = X; >134. Run the overdue cronjob from within your shell >perl misc/cronjobs/recall/overdue_recalls.pl >135. Go to Circulation -> Overdue recalls >136. Confirm your recall is showing here now as the recall has been marked Overdue > >CIRCULATION > >137. Check in Item A. >138. When the recall box pops up, click Ignore. >139. Check out Item A to Borrower B. You should see a yellow confirmation box, saying that another borrower has recalled the item you are trying to check out. >140. Click "No don't check out" and confirm the item isn't checked out and the recall remains. >141. Repeat Step 139. >142. Click "Yes check out" and confirm the item is checked out and the recall remains. >143. When Borrower B's checkout table loads, confirm that you cannot renew or check in the item from the Checkouts table because there is a 'Recalled' link which takes you to the recalls tab for that biblio. >144. Repeat Steps 137-139. >145. Select "Cancel recall" and click "Yes check out" and confirm the item is checked out and the recall has been cancelled. >146. Log in to the OPAC as Borrower A. Place a recall (any level) on Biblio A. >147. Check in Item A. Confirm the recall as waiting. >148. Check out Item A to Borrower B. You should see a yellow confirmation box, saying that that another borrower has recalled the item that you are trying to check out. >149. Select "Revert waiting status" and click "Yes check out" and confirm the item is checked out and the recall status has reverted to requested. > >OTHER >150. In your terminal, enter mysql and edit the due date of the checkout to Borrower B to be before today >UPDATE issues SET date_due = NOW()-2 WHERE issue_id = X; >151. Go to Borrower A's recalls and click the Actions dropdown. >152. Click "Mark as overdue" and confirm the recall is marked as overdue manually. > >153. Go to Tools -> Log Viewer. Check only the Recalls module, and leave all other parameters, and click Submit. >154. Confirm all of the recalls actions that have been made are correctly logged. > >Note: recalls messaging preferences are introduced in Bug 23781. >The recall feature is fully documented at: https://wiki.koha-community.org/wiki/Catalyst_IT_Recalls > >Signed-off-by: David Nind <david@davidnind.com> >--- > catalogue/detail.pl | 6 + > circ/circulation.pl | 7 +- > circ/returns.pl | 97 ++++++++-- > circ/transferstoreceive.pl | 7 + > .../prog/en/includes/biblio-view-menu.inc | 3 + > .../intranet-tmpl/prog/en/includes/circ-menu.inc | 3 + > .../intranet-tmpl/prog/en/includes/circ-nav.inc | 8 + > .../prog/en/includes/patron-title.inc | 1 + > .../intranet-tmpl/prog/en/includes/recalls.inc | 134 ++++++++++++++ > .../prog/en/modules/catalogue/detail.tt | 15 +- > .../prog/en/modules/catalogue/results.tt | 6 + > .../prog/en/modules/cataloguing/addbooks.tt | 1 + > .../prog/en/modules/circ/circulation-home.tt | 12 ++ > .../prog/en/modules/circ/circulation.tt | 51 ++++- > .../prog/en/modules/circ/printslip.tt | 2 + > .../intranet-tmpl/prog/en/modules/circ/renew.tt | 3 + > .../intranet-tmpl/prog/en/modules/circ/returns.tt | 205 ++++++++++++++++++++- > .../prog/en/modules/circ/transferstoreceive.tt | 2 + > .../prog/en/modules/members/moremember.tt | 15 ++ > .../prog/en/modules/members/recallshistory.tt | 48 +++++ > .../prog/en/modules/recalls/recalls_old_queue.tt | 56 ++++++ > .../prog/en/modules/recalls/recalls_overdue.tt | 67 +++++++ > .../prog/en/modules/recalls/recalls_queue.tt | 67 +++++++ > .../prog/en/modules/recalls/recalls_to_pull.tt | 175 ++++++++++++++++++ > .../prog/en/modules/recalls/recalls_waiting.tt | 181 ++++++++++++++++++ > .../prog/en/modules/recalls/request.tt | 63 +++++++ > .../prog/en/modules/reserve/request.tt | 4 +- > .../intranet-tmpl/prog/en/modules/tools/viewlog.tt | 15 +- > koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 15 +- > koha-tmpl/intranet-tmpl/prog/js/recalls.js | 175 ++++++++++++++++++ > members/moremember.pl | 2 + > members/recallshistory.pl | 47 +++++ > recalls/recall_pickup_slip.pl | 74 ++++++++ > recalls/recalls_old_queue.pl | 47 +++++ > recalls/recalls_overdue.pl | 61 ++++++ > recalls/recalls_queue.pl | 57 ++++++ > recalls/recalls_to_pull.pl | 126 +++++++++++++ > recalls/recalls_waiting.pl | 76 ++++++++ > recalls/request.pl | 65 +++++++ > reserve/request.pl | 3 + > svc/checkouts | 22 +++ > svc/recall | 89 +++++++++ > tools/letter.pl | 2 +- > tools/viewlog.pl | 10 + > 44 files changed, 2102 insertions(+), 23 deletions(-) > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/recalls.inc > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/recallshistory.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_old_queue.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_overdue.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_queue.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_waiting.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt > create mode 100644 koha-tmpl/intranet-tmpl/prog/js/recalls.js > create mode 100755 members/recallshistory.pl > create mode 100755 recalls/recall_pickup_slip.pl > create mode 100755 recalls/recalls_old_queue.pl > create mode 100755 recalls/recalls_overdue.pl > create mode 100755 recalls/recalls_queue.pl > create mode 100755 recalls/recalls_to_pull.pl > create mode 100755 recalls/recalls_waiting.pl > create mode 100755 recalls/request.pl > create mode 100755 svc/recall > >diff --git a/catalogue/detail.pl b/catalogue/detail.pl >index 8049906bac..276273fc20 100755 >--- a/catalogue/detail.pl >+++ b/catalogue/detail.pl >@@ -411,6 +411,12 @@ foreach my $item (@items) { > $item->{cover_images} = $item_object->cover_images; > } > >+ my $recall = Koha::Recalls->find({ itemnumber => $item->{itemnumber}, old => undef }); >+ if ( defined $recall ) { >+ $item->{recalled} = 1; >+ $item->{recall} = $recall; >+ } >+ > if ($currentbranch and C4::Context->preference('SeparateHoldings')) { > if ($itembranchcode and $itembranchcode eq $currentbranch) { > push @itemloop, $item; >diff --git a/circ/circulation.pl b/circ/circulation.pl >index 44f87b6281..1fe54e3c1c 100755 >--- a/circ/circulation.pl >+++ b/circ/circulation.pl >@@ -177,6 +177,8 @@ if ( $restoreduedatespec && $restoreduedatespec eq "highholds_empty" ) { > } > my $issueconfirmed = $query->param('issueconfirmed'); > my $cancelreserve = $query->param('cancelreserve'); >+my $cancel_recall = $query->param('cancel_recall'); >+my $recall_id = $query->param('recall_id'); > my $debt_confirmed = $query->param('debt_confirmed') || 0; # Don't show the debt error dialog twice > my $charges = $query->param('charges') || q{}; > >@@ -415,7 +417,8 @@ if (@$barcodes) { > } > unless($confirm_required) { > my $switch_onsite_checkout = exists $messages->{ONSITE_CHECKOUT_WILL_BE_SWITCHED}; >- my $issue = AddIssue( $patron->unblessed, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, } ); >+ my $recall_id = $messages->{RECALLED}; >+ my $issue = AddIssue( $patron->unblessed, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, cancel_recall => $cancel_recall, recall_id => $recall_id, } ); > $template_params->{issue} = $issue; > $session->clear('auto_renew'); > $inprocess = 1; >@@ -462,6 +465,8 @@ if ($patron) { > $template->param( > holds_count => $holds->count(), > WaitingHolds => $waiting_holds, >+ recalls => $patron->recalls, >+ specific_patron => 1, > ); > } > >diff --git a/circ/returns.pl b/circ/returns.pl >index b58e340f85..9393f76af9 100755 >--- a/circ/returns.pl >+++ b/circ/returns.pl >@@ -81,6 +81,15 @@ if ( $query->param('print_slip') ) { > ); > } > >+# print a recall slip >+if ( $query->param('recall_slip') ) { >+ $template->param( >+ recall_slip => 1, >+ recall_id => scalar $query->param('recall_id'), >+ ); >+} >+ >+ > ##################### > #Global vars > my $userenv = C4::Context->userenv; >@@ -173,6 +182,24 @@ if ( $query->param('reserve_id') ) { > } > } > >+if ( $query->param('recall_id') ) { >+ my $recall = Koha::Recalls->find( scalar $query->param('recall_id') ); >+ my $itemnumber = $query->param('itemnumber'); >+ my $return_branch = $query->param('returnbranch'); >+ >+ my $expirationdate = $recall->calc_expirationdate; >+ my $item; >+ if ( !$recall->item_level_recall ) { >+ $item = Koha::Items->find( $itemnumber ); >+ } >+ >+ if ( $recall->branchcode ne $return_branch ) { >+ $recall->start_transfer({ item => $item }) if !$recall->in_transit; >+ } else { >+ $recall->set_waiting({ item => $item }) if !$recall->waiting; >+ } >+} >+ > my $borrower; > my $returned = 0; > my $messages; >@@ -229,7 +256,11 @@ if ($dotransfer){ > > if ($canceltransfer){ > DeleteTransfer($itemnumber); >- if($dest eq "ttr"){ >+ my $recall_transfer_deleted = Koha::Recalls->find({ itemnumber => $itemnumber, status => 'T' }); >+ if ( defined $recall_transfer_deleted ) { >+ $recall_transfer_deleted->revert_transfer; >+ } >+ if($dest and $dest eq "ttr"){ > print $query->redirect("/cgi-bin/koha/circ/transferstoreceive.pl"); > exit; > } else { >@@ -267,16 +298,17 @@ if ($barcode) { > my $checkout = $item->checkout; > my $biblio = $item->biblio; > $template->param( >- title => $biblio->title, >- homebranch => $item->homebranch, >- holdingbranch => $item->holdingbranch, >- returnbranch => $returnbranch, >- author => $biblio->author, >- itembarcode => $item->barcode, >- itemtype => $item->effective_itemtype, >- ccode => $item->ccode, >- itembiblionumber => $biblio->biblionumber, >- biblionumber => $biblio->biblionumber, >+ title => $biblio->title, >+ homebranch => $item->homebranch, >+ holdingbranch => $item->holdingbranch, >+ returnbranch => $returnbranch, >+ author => $biblio->author, >+ itemnumber => $item->itemnumber, >+ itembarcode => $item->barcode, >+ itemtype => $item->effective_itemtype, >+ ccode => $item->ccode, >+ itembiblionumber => $biblio->biblionumber, >+ biblionumber => $biblio->biblionumber, > additional_materials => $materials, > issue => $checkout, > ); >@@ -360,6 +392,7 @@ $template->param( inputloop => \@inputloop ); > my $found = 0; > my $waiting = 0; > my $reserved = 0; >+my $recalled = 0; > > # new op dev : we check if the document must be returned to his homebranch directly, > # if the document is transferred, we have warning message . >@@ -412,7 +445,7 @@ if ( $messages->{'WrongTransfer'} and not $messages->{'WasTransfered'}) { > # > # reserve found and item arrived at the expected branch > # >-if ( $messages->{'ResFound'}) { >+if ( $messages->{'ResFound'} ) { > my $reserve = $messages->{'ResFound'}; > my $patron = Koha::Patrons->find( $reserve->{borrowernumber} ); > my $holdmsgpreferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $reserve->{'borrowernumber'}, message_name => 'Hold_Filled' } ); >@@ -464,6 +497,40 @@ if ( $messages->{'ResFound'}) { > ); > } > >+if ( $messages->{RecallFound} ) { >+ my $recall = $messages->{RecallFound}; >+ if ( dt_from_string( $recall->timestamp ) == dt_from_string ) { >+ # we just updated this recall >+ $template->param( recall => $recall ); >+ } else { >+ my $transferbranch = $messages->{RecallNeedsTransfer}; >+ my $transfertodo = ( !$transferbranch or $transferbranch eq $recall->library->branchcode ) ? undef : 1; >+ $template->param( >+ found => 1, >+ recall => $recall, >+ recalled => $recall->waiting ? 0 : 1, >+ transfertodo => $transfertodo, >+ waitingrecall => $recall->waiting ? 1 : 0, >+ ); >+ } >+} >+ >+if ( $messages->{TransferredRecall} ) { >+ my $recall = $messages->{TransferredRecall}; >+ >+ # confirm transfer has arrived at the branch >+ my $transfer = Koha::Item::Transfers->search({ datearrived => { '!=' => undef }, itemnumber => $recall->itemnumber }, { order_by => { -desc => 'datearrived' } })->next; >+ >+ # if transfer has completed, show popup to confirm as waiting >+ if ( defined $transfer and $transfer->tobranch eq $recall->branchcode ) { >+ $template->param( >+ found => 1, >+ recall => $recall, >+ recalled => 1, >+ ); >+ } >+} >+ > # Error Messages > my @errmsgloop; > foreach my $code ( keys %$messages ) { >@@ -545,6 +612,12 @@ foreach my $code ( keys %$messages ) { > } > elsif ( $code eq 'ReturnClaims' ) { > $template->param( ReturnClaims => $messages->{ReturnClaims} ); >+ } elsif ( $code eq 'RecallFound' ) { >+ ; >+ } elsif ( $code eq 'RecallNeedsTransfer' ) { >+ ; >+ } elsif ( $code eq 'TransferredRecall' ) { >+ ; > } else { > die "Unknown error code $code"; # note we need all the (empty) elsif's above, or we die. > # This forces the issue of staying in sync w/ Circulation.pm >diff --git a/circ/transferstoreceive.pl b/circ/transferstoreceive.pl >index bbf25368ae..dadb81974e 100755 >--- a/circ/transferstoreceive.pl >+++ b/circ/transferstoreceive.pl >@@ -116,6 +116,13 @@ while ( my $library = $libraries->next ) { > if ( my $first_hold = $holds->next ) { > $getransf{patron} = Koha::Patrons->find( $first_hold->borrowernumber ); > } >+ >+ # check for a recall for this transfer >+ my $recall = $item->recall; >+ if ( defined $recall ) { >+ $getransf{recall} = $recall; >+ } >+ > push( @transferloop, \%getransf ); > } > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-view-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-view-menu.inc >index 2080b07707..4ef1173213 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-view-menu.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-view-menu.inc >@@ -41,5 +41,8 @@ > <a href="/cgi-bin/koha/catalogue/issuehistory.pl?biblionumber=[% biblio_object_id | url %]" >Checkout history</a></li> > [% IF ( CAN_user_tools_view_system_logs ) %][% IF ( logview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/tools/viewlog.pl?do_it=1&modules=CATALOGUING&action=MODIFY&object=[% biblio_object_id | url %]&object_type=biblio">Modification log</a> </li>[% END %] > [% IF ( CAN_user_stockrotation_manage_rota_items && Koha.Preference('StockRotation') ) %][% IF ( stockrotationview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/catalogue/stockrotation.pl?biblionumber=[% biblio_object_id | uri %]">Rota</a> </li>[% END %] >+ [% IF ( Koha.Preference('UseRecalls') && CAN_user_recalls ) %] >+ [% IF ( recallsview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/recalls/request.pl?biblionumber=[% biblio_object_id | url %]">Recalls ([% Biblio.RecallsCount( biblio_object_id ) | html %])</a></li> >+ [% END %] > </ul> > </div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >index 27b4783e8e..6af7351033 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc >@@ -175,6 +175,9 @@ > [% IF Koha.Preference('ILLModule') && CAN_user_ill %] > [% IF illview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/ill-requests.pl?borrowernumber=[% patron.borrowernumber | uri %]">ILL requests history</a></li> > [% END %] >+ [% IF Koha.Preference('UseRecalls') && CAN_user_recalls %] >+ [% IF recallsview %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/recallshistory.pl?borrowernumber=[% patron.borrowernumber | uri %]">Recalls history</a></li> >+ [% END %] > </ul></div> > > <!-- Modal --> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-nav.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-nav.inc >index 14931325fd..99b882c76a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-nav.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-nav.inc >@@ -46,6 +46,14 @@ > [% IF Koha.Preference('OnSiteCheckouts') %] > <li><a href="/cgi-bin/koha/circ/on-site_checkouts.pl">Pending on-site checkouts</a></li> > [% END %] >+ >+ [% IF Koha.Preference('UseRecalls') and CAN_user_recalls %] >+ <li><a href="/cgi-bin/koha/recalls/recalls_queue.pl" title="All active recalls">Recalls queue</a></li> >+ <li><a href="/cgi-bin/koha/recalls/recalls_to_pull.pl" title="Recalls that could be filled but have not been set waiting">Recalls to pull</a></li> >+ <li><a href="/cgi-bin/koha/recalls/recalls_overdue.pl" title="Recalled items that are overdue to be returned">Overdue recalls</a></li> >+ <li><a href="/cgi-bin/koha/recalls/recalls_waiting.pl" title="Recalled items awaiting pickup">Recalls awaiting pickup</a></li> >+ <li><a href="/cgi-bin/koha/recalls/recalls_old_queue.pl" title="Inactive recalls">Old recalls</a></li> >+ [% END %] > </ul> > > </div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc >index 71a293588a..5a9b14d727 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc >@@ -53,6 +53,7 @@ > [%- END -%] > [%- IF hide_patron_infos_if_needed AND ( display_patron_name OR display_cardnumber ) -%] > [%- IF link_to == 'circulation_reserves' %]<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% data.borrowernumber | uri %]#reserves"> >+ [%- ELSIF link_to == 'circulation_recalls' %]<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% data.borrowernumber | uri %]#recalls"> > [%- ELSE %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% data.borrowernumber | uri %]"> > [%- END -%] > [%- END -%] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/recalls.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/recalls.inc >new file mode 100644 >index 0000000000..52b67ffbbc >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/recalls.inc >@@ -0,0 +1,134 @@ >+[% USE Branches %] >+<div id="recalls"> >+[% IF recalls.count %] >+ <table id="recalls-table"> >+ <thead> >+ <tr> >+ [% IF checkboxes %]<th class="recall-checkbox nosort"> </th>[% END %] >+ <th class="recall-title anti-the">Title</th> >+ [% UNLESS specific_patron %]<th class="recall-patron">Requested by</th>[% END %] >+ <th class="recall-date">Placed on</th> >+ <th class="recall-expiry">Expires on</th> >+ <th class="recall-branch">Pickup location</th> >+ <th class="recall-status">Status</th> >+ [% UNLESS viewing_old %]<th class="recall-duedate">Due date</th>[% END %] >+ [% UNLESS viewing_old %]<th class="recall-actions nosort"> </th>[% END %] >+ </tr> >+ </thead> >+ >+ <tbody> >+ [% FOREACH recall IN recalls %] >+ [% IF recall.old %]<tr class="old">[% ELSE %]<tr>[% END %] >+ >+ [% IF checkboxes %] >+ <td class="recall-checkbox"> >+ [% IF recall.old %] >+ >+ [% ELSE %] >+ <input type="checkbox" value="[% recall.recall_id | html %]" name="recall_ids"> >+ [% END %] >+ </td> >+ [% END %] >+ >+ <td class="recall-title"> >+ <b><a class="recall-title" href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% recall.biblionumber | html %]"> >+ [% recall.biblio.title | html %] >+ [% FOREACH s IN recall.biblio.subtitle %] >+ [% s | html %] >+ [% END %] >+ </a></b> >+ [% IF recall.item %][% recall.item.barcode | html %][% END %] >+ [% recall.biblio.author | html %] >+ </td> >+ >+ [% UNLESS specific_patron %] >+ <td class="recall-patron"> >+ <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% recall.borrowernumber | uri %]">[% recall.patron.firstname | html %] [% recall.patron.surname | html %] ([% recall.patron.cardnumber | html %])</a> >+ </td> >+ [% END %] >+ >+ <td class="recall-date"> >+ [% recall.recalldate | $KohaDates %] >+ </td> >+ >+ <td class="recall-expiry"> >+ [% IF ( recall.expirationdate ) %] >+ [% recall.expirationdate | $KohaDates %] >+ [% ELSIF ( !recall.old ) %] >+ Never expires >+ [% ELSE %] >+ - >+ [% END %] >+ </td> >+ >+ <td class="recall-branch"> >+ [% recall.library.branchname | html %] >+ </td> >+ >+ <td class="recall-status"> >+ [% IF ( recall.in_transit ) %] >+ In transit to [% recall.library.branchname | html %] >+ [% ELSIF ( recall.waiting ) %] >+ Ready for pickup >+ [% ELSIF ( recall.expired ) %] >+ Expired on [% recall.expirationdate | $KohaDates %] >+ [% ELSIF ( recall.cancelled ) %] >+ Cancelled on [% recall.cancellationdate | $KohaDates %] >+ [% ELSIF ( recall.overdue ) %] >+ Overdue to be returned >+ [% ELSIF ( recall.finished ) %] >+ Fulfilled >+ [% ELSE %] >+ Requested >+ [% END %] >+ </td> >+ >+ [% UNLESS viewing_old %] >+ <td class="recall-duedate"> >+ [% IF recall.requested and recall.checkout %] >+ Due to be returned by [% recall.checkout.date_due | $KohaDates %] >+ [% ELSIF recall.waiting and RECALL.expirationdate %] >+ Pick up by [% RECALL.expirationdate | $KohaDates %] >+ [% ELSE %] >+ - >+ [% END %] >+ </td> >+ [% END %] >+ >+ [% UNLESS viewing_old %] >+ <td class="recall-cancel actions"> >+ [% IF recall.old %] >+ >+ [% ELSE %] >+ <div class="btn-group"> >+ <a class="btn btn-sm dropdown-toggle" data-toggle="dropdown" href="#"> Actions <span class="caret"></span></a> >+ <ul class="dropdown-menu pull-right"> >+ [% IF ( recall.requested or recall.overdue ) %] >+ <li><a class="cancel_recall" data-id="[% recall.recall_id | html %]" data-action="cancel"><i class="fa fa-times"></i> Cancel</a></li> >+ [% IF ( recall.should_be_overdue ) %] >+ <li><a class="overdue_recall" data-id="[% recall.recall_id | html %]" data-action="overdue"><i class="fa fa-hourglass-end"></i> Mark as overdue</a></li> >+ [% END %] >+ [% ELSIF ( recall.waiting ) %] >+ <li><a class="revert_recall" data-id="[% recall.recall_id | html %]" data-action="revert"><i class="fa fa-undo"></i> Revert waiting</a></li> >+ <li><a class="expire_recall" data-id="[% recall.recall_id | html %]" data-action="expire"><i class="fa fa-times"></i> Expire</a></li> >+ [% ELSIF ( recall.in_transit ) %] >+ <li><a class="transit_recall" data-id="[% recall.recall_id | html %]" data-action="transit"><i class="fa fa-times"></i> Cancel recall and return to: [% Branches.GetName(recall.item.homebranch) | html %]</a></li> >+ [% END %] >+ </ul> >+ </div> >+ [% END %] >+ </td> >+ [% END %] >+ >+ </tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% ELSE %] >+ [% IF patron.borrowernumber %] >+ <div class="dialog message">Patron has no recalls.</div> >+ [% ELSE %] >+ <div class="dialog message">There are no recalls to show.</div> >+ [% END %] >+ [% END %] >+</div> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >index 55f13b75d8..90c93de58d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >@@ -473,14 +473,22 @@ Note that permanent location is a code, and location may be an authval. > <span class="holdonitem">There is an item level hold on this item (priority = [% hold.priority | html %]).</span> > [% END %] > [% END %] >- [% UNLESS ( item.itemnotforloan || item.notforloan_per_itemtype || item.onloan || item.itemlost || item.withdrawn || item.damaged || item.transfertwhen || hold ) %] >- <span class="available">Available</span> >+ >+ [% IF item.recalled %] >+ [% IF item.recall.waitingdate %] >+ Waiting at [% Branches.GetName( item.recall.branchcode ) | html %] since [% item.recall.waitingdate | $KohaDates %] >+ [% ELSE %] >+ Item recalled by <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% item.recall.borrowernumber | uri %]">[% item.recall.patron.firstname | html %] [% item.recall.patron.surname | html %] ([% item.recall.patron.cardnumber | html %])</a> on [% item.recall.recalldate | $KohaDates %] >+ [% END %] >+ [% END %] >+ >+ [% UNLESS ( item.itemnotforloan || item.notforloan_per_itemtype || item.onloan || item.itemlost || item.withdrawn || item.damaged || item.transfertwhen || hold || item.recalled ) %] >+ Available > [% END %] > > [% IF ( item.restricted ) %] > <span class="restricted">([% item.restrictedvalue | html %])</span> > [% END %] >- > </td> > <td class="datelastseen"><span title="[% item.datelastseen | html %]">[% item.datelastseen | $KohaDates %]</span></td> > <td class="dateaccessioned"><span title="[% item.dateaccessioned | html %]">[% item.dateaccessioned | $KohaDates %]</span></td> >@@ -995,6 +1003,7 @@ Note that permanent location is a code, and location may be an authval. > [% MACRO jsinclude BLOCK %] > [% INCLUDE 'catalog-strings.inc' %] > [% Asset.js("js/catalog.js") | $raw %] >+ [% Asset.js("js/recalls.js") | $raw %] > [% Asset.js("js/coce.js") | $raw %] > <script> > var interface = "[% interface | html %]"; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt >index d135b88c5d..a42e96520d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt >@@ -505,6 +505,9 @@ > Holds ([% Biblio.HoldsCount( SEARCH_RESULT.biblionumber ) | html %]) > [% END %] > [% END # /IF SEARCH_RESULT.norequests %] >+ [% IF Koha.Preference('UseRecalls') and CAN_user_recalls %] >+ | <a id="recall_[% SEARCH_RESULT.biblionumber | html %]" href="/cgi-bin/koha/recalls/request.pl?biblionumber=[% SEARCH_RESULT.biblionumber | html %]">Recalls ([% Biblio.RecallsCount( SEARCH_RESULT.biblionumber ) | html %])</a> >+ [% END %] > > [% IF Koha.Preference('intranetbookbag') == 1 %] > [% IF ( SEARCH_RESULT.incart ) %] >@@ -640,6 +643,9 @@ > [% IF ( other_items_loo.intransit ) %] > (In transit) > [% END %] >+ [% IF ( other_items_loo.recalled ) %] >+ (Recalled) >+ [% END %] > [% IF ( other_items_loo.onhold ) %] > (On hold) > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbooks.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbooks.tt >index 6a2b34e6ac..df581ec97d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbooks.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbooks.tt >@@ -118,6 +118,7 @@ > [% IF ( resultsloo.onloancount ) %] Checked out ([% resultsloo.onloancount | html %]),<br /> [% END %] > [% IF ( resultsloo.withdrawncount ) %] Withdrawn ([% resultsloo.withdrawncount | html %]),<br /> [% END %] > [% IF ( resultsloo.itemlostcount ) %] Lost ([% resultsloo.itemlostcount | html %])<br />[% END %] >+ [% IF ( resultsloo.recalledcount ) %] Waiting to fill recall ([% resultsloo.recalled | html %])[% END %] > [% IF ( resultsloo.onholdcount ) %] Waiting on hold ([% resultsloo.onholdcount | html %])[% END %] > </span> > <span class="notforloan"> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt >index 57eaad8178..0667c1db0e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation-home.tt >@@ -74,6 +74,18 @@ > <a class="circ-button" href="/cgi-bin/koha/circ/reserveratios.pl"><i class="fa fa-line-chart"></i> Hold ratios</a> > </li> > </ul> >+ >+ [% IF Koha.Preference('UseRecalls') and CAN_user_recalls %] >+ <h3>Recalls</h3> >+ >+ <ul class="buttons-list"> >+ <li><a class="circ-button" href="/cgi-bin/koha/recalls/recalls_queue.pl" title="All active recalls"><i class="fa fa-tasks"></i> Recalls queue</a></li> >+ <li><a class="circ-button" href="/cgi-bin/koha/recalls/recalls_to_pull.pl" title="Recalls that could be filled but have not been set waiting"><i class="fa fa-hand-grab-o"></i> Recalls to pull</a></li> >+ <li><a class="circ-button" href="/cgi-bin/koha/recalls/recalls_overdue.pl" title="Recalled items that are overdue to be returned"><i class="fa fa-clock-o"></i> Overdue recalls</a></li> >+ <li><a class="circ-button" href="/cgi-bin/koha/recalls/recalls_waiting.pl" title="Recalled items awaiting pickup"><i class="fa fa-calendar"></i> Recalls awaiting pickup</a></li> >+ <li><a class="circ-button" href="/cgi-bin/koha/recalls/recalls_old_queue.pl" title="Inactive recalls"><i class="fa fa-tasks"></i> Old recalls</a></li> >+ </ul> >+ [% END %] > </div> > > <!-- Add the extra clearfix for only the required viewport --> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >index e0ea618df2..bc7b2bfcb7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >@@ -214,6 +214,15 @@ > Please confirm that the accompanying materials are present: [% ADDITIONAL_MATERIALS | html %] > </li> > [% END %] >+ >+ [% IF RECALLED %] >+ [% IF RECALLED.waiting %] >+ <li>Item <i>[% RECALLED.biblio.title | html %]</i> ([% RECALLED.item.barcode | html %]) has been waiting for <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% RECALLED.borrowernumber | uri %]">[% RECALLED.patron.firstname | html %] [% RECALLED.patron.surname | html %]</a> ([% RECALLED.patron.cardnumber | html %]) at [% Branches.GetName( RECALLED.branchcode ) | html %] since [% RECALLED.waitingdate | $KohaDates %]</li> >+ [% ELSIF RECALLED.requested or RECALLED.overdue %] >+ <li>Item <i>[% RECALLED.biblio.title | html %]</i> [% IF RECALLED.item %]([% RECALLED.item.barcode | html %])[% END %] has been recalled by <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% RECALLED.borrowernumber | uri %]">[% RECALLED.patron.firstname | html %] [% RECALLED.patron.surname | html %]</a> ([% RECALLED.patron.cardnumber | html %]) at [% Branches.GetName( RECALLED.branchcode ) | html %] since [% RECALLED.recalldate | $KohaDates %]</li> >+ [% END %] >+ [% END %] >+ > </ul> > > [% IF CAN_user_circulate_force_checkout or HIGHHOLDS %] >@@ -263,6 +272,21 @@ > </p> > [% END %] > >+ [% IF ( RECALLED ) %] >+ <p> >+ <label for="cancelrecall">Cancel recall</label> >+ <input type="radio" value="cancel" name="cancel_recall" id="cancelrecall" /> >+ <input type="hidden" value="[% RECALLED.recall_id | html %]" name="recall_id" /> >+ </p> >+ [% IF RECALLED.waiting %] >+ <p> >+ <label for="revertrecall">Revert waiting status</label> >+ <input type="radio" value="revert" name="cancel_recall" id="revertrecall" checked="checked"/> >+ <input type="hidden" value="[% RECALLED.recall_id | html %]" name="recall_id" /> >+ </p> >+ [% END %] >+ [% END %] >+ > <input type="hidden" name="barcode" value="[% barcode | html %]" /> > <input type="hidden" name="borrowernumber" value="[% patron.borrowernumber | html %]" /> > <input type="hidden" name="issueconfirmed" value="1" /> >@@ -303,6 +327,12 @@ > </form> > [% END %] > >+ [% IF ( RECALLED ) %] >+ <form method="get" action="/cgi-bin/koha/circ/circulation.pl"> >+ <button class="print" type="submit" onclick="Dopop('/cgi-bin/koha/recalls/recall_pickup_slip.pl?recall_id=[% RECALLED.recall_id | html %]');this.form.submit();"><i class="fa fa-print"></i> Don't check out and print slip (P)</button> >+ </form> >+ [% END %] >+ > <form method="get" action="/cgi-bin/koha/circ/circulation.pl"> > [% IF (forceallow) %]<input type="hidden" name="forceallow" value="1">[% END %] > <input type="hidden" name="borrowernumber" value="[% patron.borrowernumber | html %]" /> >@@ -320,7 +350,7 @@ > [% END %] > </form> > >- [% IF ( RESERVED || ISSUED_TO_ANOTHER ) && (CAN_user_reserveforothers_place_holds ) %] >+ [% IF ( RESERVED || ISSUED_TO_ANOTHER || RECALLED ) && (CAN_user_reserveforothers_place_holds ) %] > [% UNLESS noissues %] > <button type="submit" onclick="window.location.href='/cgi-bin/koha/reserve/request.pl?biblionumber=[% itembiblionumber | html %]&borrowernumber=[% patron.borrowernumber | html %]'"><i class="fa fa-sticky-note-o"></i> Cancel checkout and place a hold for [% INCLUDE 'patron-title.inc' %]</button> > [% END %] >@@ -442,6 +472,10 @@ > [% IF ( USERBLOCKEDOVERDUE ) %] > <li>Checkouts are BLOCKED because patron has overdue items.</li> > [% END %] >+ >+ [% IF ( RECALLED_INTRANSIT ) %] >+ <li>Item has been recalled and is in transit for pickup at [% Branches.GetName( RECALLED_INTRANSIT ) | html %].</li> >+ [% END %] > </ul> > > [% IF (forceallow) %] >@@ -944,6 +978,14 @@ > </a> > </li> > [% END %] >+ >+ [% IF Koha.Preference('UseRecalls') %] >+ <li> >+ <a href="#recalls" id="recalls-tab"> >+ [% recalls.count | html %] Recalls >+ </a> >+ </li> >+ [% END %] > </ul> > > <!-- SUMMARY : TODAY & PREVIOUS ISSUES --> >@@ -958,6 +1000,12 @@ > </div> <!-- /#clubs-tab --> > [% END %] > >+ [% IF Koha.Preference('UseRecalls') %] >+ <div id="recalls"> >+ [% INCLUDE 'recalls.inc' %] >+ </div> >+ [% END %] >+ > [% INCLUDE borrower_debarments.inc %] > > <div id="reserves"> >@@ -1204,6 +1252,7 @@ > </script> > [% INCLUDE 'str/members-menu.inc' %] > [% Asset.js("js/members-menu.js") | $raw %] >+ [% Asset.js("js/recalls.js") | $raw %] > [% END %] > > [% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt >index 78f74fd4c1..bc053f873b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt >@@ -8,6 +8,8 @@ > <title>Koha › Circulation › Transfers print receipt</title> > [% ELSIF ( caller == 'members' ) %] > <title>Koha › Patrons › Print receipt for [% borrowernumber | html %]</title> >+[% ELSIF ( caller == 'recall' ) %] >+<title>Koha › Circulation › Recall print receipt</title> > [% ELSIF ( title ) %][%# FIXME title is never defined %] > <title>Koha › Patrons › [% title | html %]</title> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt >index 3ff63d043a..d374ba50b8 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt >@@ -149,6 +149,9 @@ > [% ELSIF error == "onsite_checkout" %] > <p>Item cannot be renewed because it's an onsite checkout</p> > >+ [% ELSIF error == 'recalled' %] >+ <p>This item has been recalled.</p> >+ > [% ELSE %] > > [% error | html %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >index d60cd46087..ad4150c17d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >@@ -604,7 +604,7 @@ > [% END # /IF transfer || needstransfer %] > > <!-- case of simple return no issue or transfer but with a reservation --> >- [% IF ( reserved ) %] >+ [% IF ( reserved and !recalled and !waitingrecall ) %] > <!-- reserved --> > <div id="hold-found2" class="modal fade audio-alert-action block"> > <div class="modal-dialog"> >@@ -716,6 +716,199 @@ > </div> <!-- /.modal-dialog --> > </div> <!-- /#hold-found2 --> > [% END #/IF reserved %] >+ >+ [% IF ( recalled ) %] >+ <!-- recalled --> >+ <div id="recalled" class="modal fade audio-alert-action block"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <form method="post" action="/cgi-bin/koha/circ/returns.pl" class="confirm"> >+ >+ <div class="modal-header"> >+ <h3> >+ Recall found: >+ <br/> >+ <a href="/cgi-bin/koha/catalogue/detail.pl?type=intra&biblionumber=[% recall.biblionumber | uri %]">[% recall.biblio.title | html %]</a> >+ [% IF recall.item %] >+ <div class="recall-found-barcode"> >+ (<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% recall.biblionumber | uri %]&itemnumber=[% recall.itemnumber | uri %]">[% recall.item.barcode | html %]</a>) >+ </div> >+ [% END %] >+ </h3> >+ </div> >+ >+ <div class="modal-body"> >+ [% IF ( recall.recallnotes ) %] >+ <h4>Notes:</h4> >+ <p>[% recall.recallnotes | html %]</p> >+ <hr /> >+ [% END %] >+ <h5>Recall placed by:</h5> >+ <ul> >+ <li> >+ [% INCLUDE 'patron-title.inc' patron=recall.patron hide_patron_infos_if_needed=1 invert_name=1 link_to="circulation_recalls" %] >+ <span class="patron-category"> - [% recall.patron.category.description | html %]</span> >+ </li> >+ >+ [% INCLUDE display_holdpatron_address patron=recall.patron %] >+ >+ [% IF ( recall.patron.phone ) %] >+ <li>[% recall.patron.phone | html %]</li> >+ [% END %] >+ >+ [% IF ( recall.patron.email ) %] >+ <li> >+ [% IF ( transfertodo ) %] >+ [% recall.patron.email | html %] >+ [% ELSE %] >+ <a id="boremail" href="mailto:[% recall.patron.email | html %]">[% recall.patron.email | html %]</a> >+ [% END %] >+ </li> >+ [% END %] >+ >+ [% UNLESS ( transfertodo) %] >+ [% INCLUDE display_bormessagepref %] >+ [% END %] >+ >+ [% IF ( recall.patron.is_debarred ) %] >+ <li class="error">Patron is RESTRICTED</li> >+ [% END %] >+ >+ [% IF ( recall.patron.gonenoaddress ) %] >+ <li class="error">Patron's address is in doubt</li> >+ [% END %] >+ </ul> >+ [% IF ( transfertodo ) %] >+ <h4><strong>Transfer to:</strong> [% Branches.GetName( recall.branchcode ) | html %]</h4> >+ [% ELSE %] >+ <h4><strong>Recall at</strong> [% Branches.GetName( recall.branchcode ) | html %]</h4> >+ [% END %] >+ >+ <input type="hidden" name="recall_id" value="[% recall.recall_id | html %]"> >+ <input type="hidden" name="itemnumber" value="[% itemnumber | html %]"> >+ <input type="hidden" name="returnbranch" value="[% Branches.GetLoggedInBranchcode | html %]"> >+ <input type="hidden" name="recall_slip" value="0"> >+ >+ </div> >+ >+ <div class="modal-footer"> >+ [% IF ( transfertodo ) %] >+ <button type="submit" class="btn btn-default approve"> >+ <i class="fa fa-check"></i> Confirm recall and transfer >+ </button> >+ <button type="button" class="btn btn-default print-recall"> >+ <i class="fa fa-print"></i> Print slip, transfer, and confirm >+ </button> >+ [% ELSE %] >+ <button type="submit" class="btn btn-default approve"> >+ <i class="fa fa-check"></i> Confirm recall >+ </button> >+ <button type="button" class="btn btn-default print-recall"> >+ <i class="fa fa-print"></i> Print slip and confirm >+ </button> >+ [% END %] >+ >+ <button data-dismiss="modal" aria-hidden="true" type="submit" class="btn btn-default deny"> >+ <i class="fa fa-times"></i> Ignore >+ </button> >+ </div> <!-- /.modal-footer --> >+ </form> <!-- /.confirm --> >+ </div> <!-- /.modal-content --> >+ </div> <!-- /.modal-dialog --> >+ </div> <!-- /#recalled --> >+ [% END #/IF recalled %] >+ >+ [% IF ( waitingrecall ) %] >+ <!-- recalled --> >+ <div id="recalledwaiting" class="modal fade audio-alert-action block"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <form method="post" action="/cgi-bin/koha/circ/returns.pl" class="confirm"> >+ >+ <div class="modal-header"> >+ <h3> >+ Recall found (item is already waiting): >+ <br/> >+ <a href="/cgi-bin/koha/catalogue/detail.pl?type=intra&biblionumber=[% recall.biblionumber | uri %]">[% recall.biblio.title | html %]</a> >+ [% IF recall.item %] >+ <div class="recall-found-barcode"> >+ (<a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% recall.biblionumber | uri %]&itemnumber=[% recall.itemnumber | uri %]">[% recall.item.barcode | html %]</a>) >+ </div> >+ [% END %] >+ </h3> >+ </div> >+ >+ <div class="modal-body"> >+ [% IF ( recall.recallnotes ) %] >+ <h4>Notes:</h4> >+ <p>[% recall.recallnotes | html %]</p> >+ <hr /> >+ [% END %] >+ <h5>Recall placed by:</h5> >+ <ul> >+ <li> >+ [% INCLUDE 'patron-title.inc' patron=recall.patron hide_patron_infos_if_needed=1 invert_name=1 link_to="circulation_recalls" %] >+ <span class="patron-category"> - [% recall.patron.category.description | html %]</span> >+ </li> >+ >+ [% INCLUDE display_holdpatron_address patron=recall.patron %] >+ >+ [% IF ( recall.patron.phone ) %] >+ <li>[% recall.patron.phone | html %]</li> >+ [% END %] >+ >+ [% IF ( recall.patron.email ) %] >+ <li> >+ [% IF ( transfertodo ) %] >+ [% recall.patron.email | html %] >+ [% ELSE %] >+ <a id="boremail" href="mailto:[% recall.patron.email | html %]">[% recall.patron.email | html %]</a> >+ [% END %] >+ </li> >+ [% END %] >+ >+ [% UNLESS ( transfertodo) %] >+ [% INCLUDE display_bormessagepref %] >+ [% END %] >+ >+ [% IF ( recall.patron.is_debarred ) %] >+ <li class="error">Patron is RESTRICTED</li> >+ [% END %] >+ >+ [% IF ( recall.patron.gonenoaddress ) %] >+ <li class="error">Patron's address is in doubt</li> >+ [% END %] >+ </ul> >+ [% IF ( transfertodo ) %] >+ <h4><strong>Transfer to:</strong> [% Branches.GetName( recall.branchcode ) | html %]</h4> >+ [% ELSE %] >+ <h4><strong>Wait for pickup at</strong> [% Branches.GetName( recall.branchcode ) | html %]</h4> >+ [% END %] >+ >+ <input type="hidden" name="recall_id" value="[% recall.recall_id | html %]"> >+ <input type="hidden" name="itemnumber" value="[% itemnumber | html %]"> >+ <input type="hidden" name="returnbranch" value="[% Branches.GetLoggedInBranchcode | html %]"> >+ <input type="hidden" name="recall_slip" value="0"> >+ >+ </div> >+ >+ <div class="modal-footer"> >+ <button type="submit" class="btn btn-default approve"> >+ <i class="fa fa-check"></i> Confirm recall >+ </button> >+ <button type="button" class="btn btn-default print-recall"> >+ <i class="fa fa-print"></i> Print slip and confirm >+ </button> >+ >+ <button data-dismiss="modal" aria-hidden="true" type="submit" class="btn btn-default deny"> >+ <i class="fa fa-times"></i> Ignore >+ </button> >+ </div> <!-- /.modal-footer --> >+ </form> <!-- /.confirm --> >+ </div> <!-- /.modal-content --> >+ </div> <!-- /.modal-dialog --> >+ </div> <!-- /#recalledwaiting--> >+ [% END #/IF recalledwaiting %] > [% END # /IF found %] > > <div class="static_checkin_messages"> >@@ -1006,6 +1199,11 @@ > [% END %] > [% END %] > var columns_settings = [% TablesSettings.GetColumns( 'circ', 'returns', 'checkedintable', 'json' ) | $raw %] >+ >+ [% IF recall_slip %] >+ Dopop('/cgi-bin/koha/recalls/recall_pickup_slip.pl?recall_id=[% recall_id | uri %]'); >+ [% END %] >+ > var returns_table = KohaTable("checkedintable", { > "bFilter":false, > "bPaginate":false, >@@ -1113,6 +1311,11 @@ > this.form.submit(); > }); > >+ $('.print-recall').on("click",function(e){ >+ this.form.recall_slip.value = 1; >+ this.form.submit(); >+ }); >+ > $('.cancel-hold').on("click",function(e){ > this.form.cancel_reserve.value = 1; > this.form.submit(); >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt >index 0d9360f4ea..929d52cc67 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt >@@ -68,6 +68,8 @@ > [% reser.patron.first_valid_email_address | html %] > </a> > [% END %] >+ [% ELSIF ( reser.recall ) %] >+ Recall requested by <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% reser.recall.borrowernumber | uri %]">[% reser.recall.patron.surname | html %][% IF reser.recall.patron.firstname %], [% reser.recall.patron.firstname | html %][% END %] ([% reser.recall.patron.cardnumber | html %])</a> > [% ELSE %] > <p>None</p> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >index 7b7fd26e67..2a160b068a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >@@ -795,6 +795,14 @@ > </a> > </li> > [% END %] >+ >+ [% IF Koha.Preference('UseRecalls') %] >+ <li> >+ <a href="#recalls" id="recalls-tab"> >+ [% recalls.count | html %] Recalls >+ </a> >+ </li> >+ [% END %] > </ul> > > [% INCLUDE "checkouts-table.inc" %] >@@ -817,6 +825,12 @@ > </div> > [% END %] > >+ [% IF Koha.Preference('UseRecalls') %] >+ <div id="recalls"> >+ [% INCLUDE 'recalls.inc' %] >+ </div> >+ [% END %] >+ > [% INCLUDE borrower_debarments.inc %] > > [% IF ( CAN_user_circulate_circulate_remaining_permissions ) %] >@@ -941,6 +955,7 @@ > [% Asset.js("js/holds.js") | $raw %] > [% INCLUDE 'str/members-menu.inc' %] > [% Asset.js("js/members-menu.js") | $raw %] >+ [% Asset.js("js/recalls.js") | $raw %] > [% Asset.js("js/messaging-preference-form.js") | $raw %] > <script> > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/recallshistory.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/recallshistory.tt >new file mode 100644 >index 0000000000..b1f3c62233 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/recallshistory.tt >@@ -0,0 +1,48 @@ >+[% USE raw %] >+[% USE KohaDates %] >+[% USE Koha %] >+[% USE Asset %] >+[% SET footerjs = 1 %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Recalls history for [% INCLUDE 'patron-title.inc' %]</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+ >+<body id="recalls_history" class="pat"> >+ [% INCLUDE 'header.inc' %] >+ [% INCLUDE 'patron-search.inc' %] >+ >+ <div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> › >+ <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › >+ Recalls history for [% INCLUDE 'patron-title.inc' %] >+ </div> >+ <div class="main container-fluid"> >+ <div class="row"> >+ <div class="col-sm-10 col-sm-push-2"> >+ <main> >+ [% INCLUDE 'members-toolbar.inc' %] >+ <h1>Recalls history</h1> >+ [% IF Koha.Preference('UseRecalls') %] >+ <input type="checkbox" id="hide_old" name="hide_old" checked="checked"> >+ <label for="hide_old">Show old recalls</label> >+ [% INCLUDE 'recalls.inc' %] >+ [% ELSE %] >+ <div class="dialog message">Recalls have not been enabled. Enable the <a href="/cgi-bin/koha/admin/preferences.pl?tab=circulation">UseRecalls</a> system preference to use recalls.</div> >+ [% END %] >+ </main> >+ </div> >+ <div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'circ-menu.inc' %] >+ </aside> >+ </div> >+ </div> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% Asset.js("js/recalls.js") | $raw %] >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_old_queue.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_old_queue.tt >new file mode 100644 >index 0000000000..e645bb7875 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_old_queue.tt >@@ -0,0 +1,56 @@ >+[% USE raw %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% USE Asset %] >+[% SET footerjs = 1 %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Circulation › Old recalls</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+<body id="circ_recalls_old_queue" class="circ"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> >+ › <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> >+ › <a href="/cgi-bin/koha/recalls/recalls_old_queue.pl">Old recalls</a> >+</div> >+ >+<div class="main container-fluid"> >+ <div class="row"> >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-10 col-sm-push-2"> >+ [% ELSE %] >+ <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> >+ [% END %] >+ <main> >+ >+ <h1>Old recalls</h1> >+ [% IF Koha.Preference('UseRecalls') %] >+ [% INCLUDE 'recalls.inc' %] >+ [% ELSE %] >+ <div class="dialog message">Recalls have not been enabled. Enable the <a href="/cgi-bin/koha/admin/preferences.pl?tab=circulation">UseRecalls</a> system preference to use recalls.</div> >+ [% END %] >+ >+ </main> >+ </div> <!-- /.col-etc --> >+ >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'circ-nav.inc' %] >+ </aside> >+ </div> <!-- /.col-sm-2.col-sm-pull-10 --> >+ [% END %] >+ >+ </div> <!-- /.row --> >+</div> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% Asset.js("js/recalls.js") | $raw %] >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_overdue.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_overdue.tt >new file mode 100644 >index 0000000000..86c3a98207 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_overdue.tt >@@ -0,0 +1,67 @@ >+[% USE raw %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% USE Asset %] >+[% SET footerjs = 1 %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Circulation › Overdue recalls</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+<body id="circ_overdue_recalls" class="circ"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> >+ › <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> >+ › <a href="/cgi-bin/koha/recalls/recalls_overdue.pl">Overdue recalls</a> >+</div> >+ >+<div class="main container-fluid"> >+ <div class="row"> >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-10 col-sm-push-2"> >+ [% ELSE %] >+ <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> >+ [% END %] >+ <main> >+ >+ <h1>Overdue recalls</h1> >+ [% IF Koha.Preference('UseRecalls') %] >+ [% IF recalls.count %] >+ <form method="post" action="/cgi-bin/koha/recalls/recalls_overdue.pl"> >+ <input type="hidden" name="op" value="cancel_multiple_recalls"> >+ <input type="checkbox" id="select_all"> <span id="select_all_text">Select all</span> >+ [% INCLUDE 'recalls.inc' %] >+ <fieldset class="action"> >+ <button type="submit" id="cancel_selected" class="btn btn-default btn-sm">Cancel selected recalls</button> >+ </fieldset> >+ </form> >+ [% ELSE %] >+ <div class="dialog message">There are no recalls to show.</div> >+ [% END %] >+ [% ELSE %] >+ <div class="dialog message">Recalls have not been enabled. Enable the <a href="/cgi-bin/koha/admin/preferences.pl?tab=circulation">UseRecalls</a> system preference to use recalls.</div> >+ [% END %] >+ >+ </main> >+ </div> <!-- /.col-etc --> >+ >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'circ-nav.inc' %] >+ </aside> >+ </div> <!-- /.col-sm-2.col-sm-pull-10 --> >+ [% END %] >+ >+ </div> <!-- /.row --> >+</div> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% INCLUDE 'datatables.inc' %] >+ [% Asset.js("js/recalls.js") | $raw %] >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_queue.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_queue.tt >new file mode 100644 >index 0000000000..e3caa919a3 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_queue.tt >@@ -0,0 +1,67 @@ >+[% USE raw %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% USE Asset %] >+[% SET footerjs = 1 %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Circulation › Recalls queue</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+<body id="circ_recalls_queue" class="circ"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> >+ › <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> >+ › <a href="/cgi-bin/koha/recalls/recalls_queue.pl">Recalls queue</a> >+</div> >+ >+<div class="main container-fluid"> >+ <div class="row"> >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-10 col-sm-push-2"> >+ [% ELSE %] >+ <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> >+ [% END %] >+ <main> >+ >+ <h1>Recalls queue</h1> >+ [% IF Koha.Preference('UseRecalls') %] >+ [% IF recalls.count %] >+ <form method="post" action="/cgi-bin/koha/recalls/recalls_queue.pl"> >+ <input type="hidden" name="op" value="cancel_multiple_recalls"> >+ <input type="checkbox" id="select_all"> <span id="select_all_text">Select all</span> >+ [% INCLUDE 'recalls.inc' %] >+ <fieldset class="action"> >+ <button type="submit" id="cancel_selected" class="btn btn-default btn-sm">Cancel selected recalls</button> >+ </fieldset> >+ </form> >+ [% ELSE %] >+ <div class="dialog message">There are no recalls to show.</div> >+ [% END %] >+ [% ELSE %] >+ <div class="dialog message">Recalls have not been enabled. Enable the <a href="/cgi-bin/koha/admin/preferences.pl?tab=circulation">UseRecalls</a> system preference to use recalls.</div> >+ [% END %] >+ >+ </main> >+ </div> <!-- /.col-etc --> >+ >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'circ-nav.inc' %] >+ </aside> >+ </div> <!-- /.col-sm-2.col-sm-pull-10 --> >+ [% END %] >+ >+ </div> <!-- /.row --> >+</div> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ [% Asset.js("js/recalls.js") | $raw %] >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt >new file mode 100644 >index 0000000000..347429e923 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt >@@ -0,0 +1,175 @@ >+[% USE raw %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% USE AuthorisedValues %] >+[% USE Branches %] >+[% USE ItemTypes %] >+[% USE Asset %] >+[% SET footerjs = 1 %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Circulation › Recalls to pull</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+<body id="circ_recalls_to_pull" class="circ"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> >+ › <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> >+ › <a href="/cgi-bin/koha/recalls/recalls_to_pull.pl">Recalls to pull</a> >+</div> >+ >+<div class="main container-fluid"> >+ <div class="row"> >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-10 col-sm-push-2"> >+ [% ELSE %] >+ <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> >+ [% END %] >+ <main> >+ >+ <h1>Recalls to pull</h1> >+ The following recalls could be fulfilled by available items. >+ >+ [% IF Koha.Preference('UseRecalls') %] >+ <div id="recalls"> >+ [% IF recalls %] >+ <table id="recalls-table"> >+ <thead> >+ <tr> >+ <th class="recall-topull">Pull this many items</th> >+ <th class="recall-items">Items available</th> >+ <th class="recall-patrons">Patrons with recalls</th> >+ <th class="recall-firstpatron">First patron</th> >+ <th class="recall-title anti-the">Title</th> >+ <th class="recall-libraries">Libraries</th> >+ <th class="recall-callnumbers">Available call numbers</th> >+ <th class="recall-copynumbers">Available copy numbers</th> >+ <th class="recall-enumeration">Available enumeration</th> >+ <th class="recall-itemtypes">Available item types</th> >+ <th class="recall-locations">Available locations</th> >+ <th class="recall-date title-string">Earliest recall date</th> >+ <th class="recall-action nosort"> </th> >+ </tr> >+ </thead> >+ <tbody> >+ [% FOREACH recall IN recalls %] >+ <tr> >+ <td class="recall-topull"><b>[% recall.pull_count | html %]</b></td> >+ <td class="recall-items">[% recall.items_count | html %]</td> >+ <td class="recall-patrons">[% recall.patrons_count | html %]</td> >+ <td class="recall-firstpatron"><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% recall.first_recall.borrowernumber | uri %]">[% recall.first_recall.patron.firstname | html %] [% recall.first_recall.patron.surname | html %]</a></td> >+ <td class="recall-title"> >+ [% INCLUDE 'biblio-default-view.inc' biblionumber=recall.first_recall.biblio.biblionumber %] >+ [% INCLUDE 'biblio-title.inc' biblio=recall.first_recall.biblio %] >+ [% IF recall.first_recall.biblio.author %] by [% recall.first_recall.biblio.author | html %][% END %] >+ </td> >+ <td class="recall-libraries"> >+ <ul> >+ [% FOREACH library IN recall.libraries %] >+ <li>[% Branches.GetName( library ) | html %]</li> >+ [% END %] >+ </ul> >+ </td> >+ <td class="recall-callnumbers"> >+ <ul> >+ [% FOREACH callnumber IN recall.callnumbers %] >+ <li>[% callnumber | html %]</li> >+ [% END %] >+ </ul> >+ </td> >+ <td class="recall-copynumbers"> >+ <ul> >+ [% FOREACH copyno IN recall.copynumbers %] >+ <li>[% copyno | html %]</li> >+ [% END %] >+ </ul> >+ </td> >+ <td class="recall-enumeration"> >+ <ul> >+ [% FOREACH enumchron IN recall.enumchrons %] >+ <li>[% enumchron | html %]</li> >+ [% END %] >+ </ul> >+ </td> >+ <td class="recall-itemtypes"> >+ <ul> >+ [% FOREACH itemtype IN recall.itemtypes %] >+ <li>[% ItemTypes.GetDescription( itemtype ) | html %]</li> >+ [% END %] >+ </ul> >+ </td> >+ <td class="recall-locations"> >+ <ul> >+ [% FOREACH loc IN recall.locations %] >+ <li>[% AuthorisedValues.GetByCode('LOC', loc) | html %]</li> >+ [% END %] >+ </ul> >+ </td> >+ <td class="recall-date"> >+ <span title="[% recall.first_recall.recalldate | html %]">[% recall.first_recall.recalldate | $KohaDates %] in [% recall.first_recall.library.branchname | html %]</span> >+ </td> >+ <td class="recall-action"> >+ <form action="/cgi-bin/koha/recalls/recalls_to_pull.pl" method="post"> >+ <input type="hidden" name="recall_id" value="[% recall.first_recall.recall_id | html %]"> >+ <input type="hidden" name="op" value="cancel"> >+ [% IF recall.first_recall.in_transit %] >+ <button type="submit" class="btn btn-default cancelreturn"><i class="fa fa-times"></i> Cancel recall and return to: [% Branches.GetName(recall.first_recall.item.homebranch) | html %]</button> >+ [% ELSE %] >+ <button type="submit" class="btn btn-default cancel"><i class="fa fa-times"></i> Cancel recall</button> >+ [% END %] >+ </form> >+ </td> >+ </tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% ELSE %] >+ <div class="dialog message">There are no recalls to pull.</div> >+ [% END %] >+ </div> >+ [% ELSE %] >+ <div class="dialog message">Recalls have not been enabled. Enable the <a href="/cgi-bin/koha/admin/preferences.pl?tab=circulation">UseRecalls</a> system preference to use recalls.</div> >+ [% END %] >+ >+ </main> >+ </div> <!-- /.col-etc --> >+ >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'circ-nav.inc' %] >+ </aside> >+ </div> <!-- /.col-sm-2.col-sm-pull-10 --> >+ [% END %] >+ >+ </div> <!-- /.row --> >+</div> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ <script> >+ $(document).ready(function(){ >+ $("#recalls-table").dataTable($.extend(true, {}, dataTablesDefaults, { >+ "aoColumnDefs": [ >+ { 'bSortable': false, 'aTargets': [ 'nosort' ] }, >+ { "sType": "title-string", "aTargets" : [ "title-string" ] }, >+ { "sType": "anti-the", "aTargets": [ "anti-the" ] } >+ ], >+ "sPaginationType": "full_numbers" >+ })); >+ >+ $(".cancelreturn").click(function(){ >+ return confirmDelete(_("Are you sure you want to remove this recall and return the item to it's home library?")); >+ }); >+ >+ $(".cancel").click(function(){ >+ return confirmDelete(_("Are you sure you want to remove this recall?")); >+ }); >+ }); >+ </script> >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_waiting.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_waiting.tt >new file mode 100644 >index 0000000000..1c113b1ee9 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_waiting.tt >@@ -0,0 +1,181 @@ >+[% USE raw %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% USE Asset %] >+[% SET footerjs = 1 %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Circulation › Recalls awaiting pickup</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+<body id="circ_recalls_awaiting_pickup" class="circ"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> >+ › <a href="/cgi-bin/koha/circ/circulation-home.pl">Circulation</a> >+ › <a href="/cgi-bin/koha/recalls/recalls_waiting.pl">Recalls awaiting pickup</a> >+</div> >+ >+<div class="main container-fluid"> >+ <div class="row"> >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-10 col-sm-push-2"> >+ [% ELSE %] >+ <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"> >+ [% END %] >+ <main> >+ <h1>Recalls awaiting pickup</h1> >+ >+ [% IF Koha.Preference('UseRecalls') %] >+ >+ <div id="results" class="toptabs"> >+ >+ <ul> >+ <li><a href="#recallswaiting">Recalls waiting: [% recalls.count | html %]</a></li> >+ <li><a href="#recallsover">Recalls waiting over [% Koha.Preference('RecallsMaxPickUpDelay') | html %] days: [% over.count | html %]</a></li> >+ </ul> >+ >+ <div id="recallswaiting"> >+ [% IF ( recalls ) %] >+ <table id="recallswaiting-table"> >+ <thead><tr> >+ <th class="recall-waitingdate title-string">Available since</th> >+ <th class="recall-title anti-the">Title</th> >+ <th class="recall-patron">Requested by</th> >+ <th class="recall-library">Pickup location</th> >+ <th class="recall-action nosort"> </th> >+ </tr></thead> >+ <tbody> >+ [% FOREACH recall IN recalls %]<tr> >+ <td class="recall-waitingdate">[% recall.waitingdate | $KohaDates %]</td> >+ <td class="recall-title"> >+ <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% recall.biblionumber | uri %]"> >+ [% recall.biblio.title | html %] >+ [% FOREACH s IN recall.biblio.subtitle %] >+ [% s | html %] >+ [% END %] >+ </a> >+ [% recall.biblio.author | html %] >+ <br><i>Barcode: [% recall.item.barcode | html %]</i> >+ </td> >+ <td class="recall-patron"> >+ <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% recall.borrowernumber | uri %]">[% recall.patron.firstname | html %] [% recall.patron.surname | html %]</a> >+ [% IF ( recall.patron.phone ) %]<br />[% recall.patron.phone | html %][% END %] >+ [% IF ( recall.patron.email ) %]<br /><a href="mailto:[% recall.patron.email | uri %]?subject=Recall waiting: [% recall.biblio.title | uri %]">[% recall.patron.email | html %]</a>[% END %] >+ </td> >+ <td class="recall-library">[% recall.library.branchname | html %]</td> >+ <td class="recall-action actions"> >+ <form action="/cgi-bin/koha/recalls/recalls_waiting.pl" method="post"> >+ <input type="hidden" name="recall_id" value="[% recall.recall_id | html %]"> >+ <input type="hidden" name="op" value="modify"> >+ <fieldset class="action"> >+ <input type="submit" name="revert" class="revert_recall" value="Revert waiting status"> >+ <input type="submit" name="expire" class="expire_recall" value="Expire recall"> >+ </fieldset> >+ </form> >+ </td> >+ </tr>[% END %] >+ </tbody> >+ </table> >+ [% ELSE %] >+ <div class="dialog message">There are no recalls to show.</div> >+ [% END %] >+ </div> <!-- recallswaiting --> >+ >+ <div id="recallsover"> >+ [% IF ( over.size ) %] >+ [% IF ( Koha.Preference('RecallsMaxPickUpDelay') ) %]<p>Recalls listed here have been awaiting pickup for more than [% Koha.Preference('RecallsMaxPickUpDelay') | html %] days.</p>[% END %] >+ <table id="recallsover-table"> >+ <thead><tr> >+ <th class="recall-waitingdate title-string">Available since</th> >+ <th class="recall-title anti-the">Title</th> >+ <th class="recall-patron">Requested by</th> >+ <th class="recall-library">Pickup location</th> >+ <th class="recall-action nosort"> </th> >+ </tr></thead> >+ <tbody> >+ [% FOREACH recall IN over %]<tr> >+ <td class="recall-waitingdate">[% recall.waitingdate | $KohaDates %]</td> >+ <td class="recall-title"> >+ <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% recall.biblionumber | uri %]"> >+ [% recall.biblio.title | html %] >+ [% FOREACH s IN recall.biblio.subtitles %] >+ [% s | html %] >+ [% END %] >+ [% recall.item.enumchron | html %] >+ </a> >+ [% recall.biblio.author | html %] >+ <br><i>Barcode: [% recall.item.barcode | html %]</i> >+ </td> >+ <td class="recall-patron"> >+ <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% recall.borrowernumber | uri %]">[% recall.patron.firstname | html %] [% recall.patron.surname | html %]</a> >+ [% IF ( recall.patron.phone ) %]<br />[% recall.patron.phone | html %][% END %] >+ [% IF ( recall.patron.email ) %]<br /><a href="mailto:[% recall.patron.email | uri %]?subject=Recall waiting: [% recall.biblio.title | uri %]">[% recall.patron.email | html %]</a>[% END %] >+ </td> >+ <td class="recall-library">[% recall.library.branchname | html %]</td> >+ <td class="recall-action actions"> >+ <form action="/cgi-bin/koha/recalls/recalls_waiting.pl" method="post"> >+ <input type="hidden" name="recall_id" value="[% recall.recall_id | html %]"> >+ <input type="hidden" name="op" value="modify"> >+ <fieldset class="action"> >+ <input type="submit" name="revert" class="revert_recall" value="Revert waiting status"> >+ <input type="submit" name="expire" class="expire_recall" value="Expire recall"> >+ </fieldset> >+ </form> >+ </td> >+ </tr>[% END %] >+ </tbody> >+ </table> >+ [% ELSE %] >+ <div class="dialog message">There are no recalls to show.</div> >+ [% END %] >+ </div> <!-- recallsover --> >+ >+ </div> <!-- results--> >+ >+ [% ELSE %] >+ <div class="dialog message">Recalls have not been enabled. Enable the <a href="/cgi-bin/koha/admin/preferences.pl?tab=circulation">UseRecalls</a> system preference to use recalls.</div> >+ [% END %] <!-- Koha.Preference('UseRecalls') --> >+ >+ </main> >+ </div> <!-- /.col-etc --> >+ >+ [% IF Koha.Preference('CircSidebar') %] >+ <div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'circ-nav.inc' %] >+ </aside> >+ </div> <!-- /.col-sm-2.col-sm-pull-10 --> >+ [% END %] >+ >+ </div> <!-- /.row --> >+</div> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+ <script> >+ $(document).ready(function() { >+ $('#results').tabs(); >+ >+ $("#recallswaiting-table, #recallsover-table").dataTable($.extend(true, {}, dataTablesDefaults, { >+ "autoWidth": false, >+ "aoColumnDefs": [ >+ { 'bSortable': false, 'aTargets': [ 'nosort' ] }, >+ ], >+ "sPaginationType": "full_numbers" >+ })); >+ >+ $(".revert_recall").click(function(e) { >+ return confirmDelete(_("Are you sure you want to revert this recall's status from Waiting?")); >+ }); >+ >+ $(".expire_recall").click(function(e) { >+ return confirmDelete(_("Are you sure you want to remove this recall?")); >+ }); >+ }); >+ </script> >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt >new file mode 100644 >index 0000000000..c085368bb3 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt >@@ -0,0 +1,63 @@ >+[% USE raw %] >+[% USE Asset %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% SET footerjs = 1 %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Circulation › Recalls › Confirm recalls</title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+<body id="recalls-request" class="catalog"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'circ-search.inc' %] >+ >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> › >+ <a href="/cgi-bin/koha/catalogue/search.pl">Catalog</a> › >+ <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber | uri %]">[% biblio.title | html %]</a> › >+ Confirm recalls on [% biblio.title | html %] >+</div> >+ >+<div class="main container-fluid"> >+<div class="row"> >+<div class="col-sm-10 col-sm-push-2"> >+<main> >+ >+ <h1>Existing recalls</h1> >+ >+ [% IF Koha.Preference('UseRecalls') %] >+ [% IF recalls.count %] >+ <form method="post" action="/cgi-bin/koha/recalls/request.pl"> >+ <input type="hidden" name="op" value="cancel_multiple_recalls"> >+ <input type="checkbox" id="select_all"> <span id="select_all_text">Select all</span> >+ [% INCLUDE 'recalls.inc' %] >+ <fieldset class="action"> >+ <button type="submit" id="cancel_selected" class="btn btn-default btn-sm">Cancel selected recalls</button> >+ </fieldset> >+ </form> >+ [% ELSE %] >+ <div class="dialog message">No recalls have been made.</div> >+ [% END %] >+ [% ELSE %] >+ <div class="dialog message">Recalls have not been enabled. Enable the <a href="/cgi-bin/koha/admin/preferences.pl?tab=circulation">UseRecalls</a> system preference to use recalls.</div> >+ [% END %] >+ >+</main> >+</div> <!-- /.col-sm-10.col-sm-push-2 --> >+ >+<div class="col-sm-2 col-sm-pull-10"> >+ <aside> >+ [% INCLUDE 'biblio-view-menu.inc' %] >+ </aside> >+</div> <!-- .col-sm-2.col-sm-pull-10 --> >+ >+</div> <!-- /.row --> >+</div> <!-- /.main.container-fluid --> >+ >+[% MACRO jsinclude BLOCK %] >+ [% Asset.js("js/recalls.js") | $raw %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'columns_settings.inc' %] >+[% END %] >+ >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >index 5dfff18595..8d312f3c77 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt >@@ -302,7 +302,7 @@ > </div> > [% END %] > >- [% IF ( exceeded_maxreserves || exceeded_holds_per_record || alreadyreserved || none_available || alreadypossession || ageRestricted ) %] >+ [% IF ( exceeded_maxreserves || exceeded_holds_per_record || alreadyreserved || none_available || alreadypossession || ageRestricted || recall ) %] > <div class="dialog alert"> > > [% UNLESS ( multi_hold ) %] >@@ -322,6 +322,8 @@ > <li> <strong>No items are available</strong> to be placed on hold.</li> > [% ELSIF ( maxreserves ) %] > <li><strong>Too many holds: </strong> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | uri %]">[% patron.firstname | html %] [% patron.surname | html %] </a> has too many holds.</li> >+ [% ELSIF ( recall ) %] >+ <li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% patron.borrowernumber | uri %]">[% patron.firstname | html %] [% patron.surname | html %]</a> has <strong>already placed a recall</strong> on this item.</li> > [% END # /IF exceeded_maxreserves %] > </ul> > [% ELSE # UNLESS multi_hold %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >index 961f3cc08e..78e4d22ada 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >@@ -96,6 +96,8 @@ > > [% CASE 'SEARCHENGINE' %]Search engine > >+[% CASE 'RECALLS' %]Recalls[% UNLESS Koha.Preference('RecallsLog') %] <i class="fa fa-warning" title="Log not enabled"></i>[% END %] >+ > [% CASE %][% module | html %] > [% END %] > [% END %] >@@ -121,6 +123,9 @@ > [% CASE 'Run' %]Run > [% CASE 'EDIT_MAPPINGS' %]Edit mappings > [% CASE 'RESET_MAPPINGS' %]Reset mappings >+[% CASE 'FULFILL' %]Fulfill >+[% CASE 'OVERDUE' %]Overdue >+[% CASE 'EXPIRE' %]Expire > [% CASE %][% action | html %] > [% END %] > [% END %] >@@ -172,7 +177,7 @@ > [% ELSE %] > <label for="moduleALL" class="viewlog"><input type="checkbox" id="moduleALL" name="modules" value=""> All</label> > [% END %] >- [% FOREACH modx IN [ 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'LETTER' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE' ] %] >+ [% FOREACH modx IN [ 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'LETTER' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE', 'RECALLS' ] %] > [% IF modules.grep(modx).size %] > <label for="module[% modx | html %]" class="viewlog"><input type="checkbox" id="module[% modx | html %]" name="modules" value="[% modx | html %]" checked="checked"> [% PROCESS translate_log_module module=modx %]</label> > [% ELSE %] >@@ -194,7 +199,7 @@ > <label for="actionALL" class="viewlog"><input type="checkbox" id="actionALL" name="actions" value=""> All</label> > [% END %] > >- [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'PATRON_NOTICE' 'CHANGE PASS' 'Run' 'EDIT_MAPPINGS' 'RESET_MAPPINGS' ] %] >+ [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'PATRON_NOTICE' 'CHANGE PASS' 'Run' 'EDIT_MAPPINGS' 'RESET_MAPPINGS' 'OVERDUE' 'EXPIRE' 'FULFILL' ] %] > [% IF actions.grep(actx).size %] > <label for="action[% actx| replace('\s+', '_') | html %]" class="viewlog"><input type="checkbox" id="action[% actx | replace('\s+', '_') | html %]" name="actions" value="[% actx | html %]" checked="checked"> [% PROCESS translate_log_action action=actx %]</label> > [% ELSE %] >@@ -316,6 +321,12 @@ > [% ELSE %] > [% loopro.object | html %] > [% END %] >+ [% ELSIF ( loopro.module == 'RECALLS' ) %] >+ [% IF loopro.recall.item_level_recall %] >+ Item-level recall on <a href="/cgi-bin/koha/catalogue/moredetail.pl?item=[% loopro.recall.itemnumber | uri %]&biblionumber=[% loopro.recall.biblionumber | uri %]&bi=[% loopro.recall.item.biblioitemnumber | uri %]">item</a> >+ [% ELSE %] >+ Biblio-level recall on <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% loopro.recall.biblionumber | uri %]">biblio</a> >+ [% END %] > [% ELSE %] > [% IF ( loopro.module == 'SERIAL' ) %] > <a href="/cgi-bin/koha/serials/subscription-detail.pl?subscriptionid=[% loopro.object | uri %]">Subscription [% loopro.object | html %] </a> >diff --git a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js >index fc67a26488..78e535feef 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js >@@ -360,6 +360,10 @@ $(document).ready(function() { > onsite_checkout += " <span class='onsite_checkout'>(" + __("On-site checkout") + ")</span>"; > } > >+ if ( oObj.recalled == 1 ) { >+ title += " - <span class='circ-hlt item-recalled'>This item has been recalled and the due date updated.</span>"; >+ } >+ > title += " " > + "<a href='/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=" > + oObj.biblionumber >@@ -453,6 +457,13 @@ $(document).ready(function() { > > if ( oObj.can_renew ) { > // Do nothing >+ } else if ( oObj.can_renew_error == "recalled" ) { >+ msg += "<span>" >+ + "<a href='/cgi-bin/koha/recalls/request.pl?biblionumber=" + oObj.biblionumber + "'>" + RECALLED + "</a>" >+ + "</span>"; >+ >+ span_style = "display: none"; >+ span_class = "renewals-allowed-recalled"; > } else if ( oObj.can_renew_error == "on_reserve" ) { > msg += "<span>" > +"<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("On hold") + "</a>" >@@ -583,7 +594,9 @@ $(document).ready(function() { > "bSortable": false, > "bVisible": AllowCirculate ? true : false, > "mDataProp": function ( oObj ) { >- if ( oObj.can_renew_error == "on_reserve" ) { >+ if ( oObj.can_renew_error == "recalled" ) { >+ return "<a href='/cgi-bin/koha/recalls/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("Recalled") + "</a>"; >+ } else if ( oObj.can_renew_error == "on_reserve" ) { > return "<a href='/cgi-bin/koha/reserve/request.pl?biblionumber=" + oObj.biblionumber + "'>" + __("On hold") + "</a>"; > } else if ( oObj.materials ) { > return "<input type='checkbox' class='confirm' id='confirm_" + oObj.itemnumber + "' name='confirm' value='" + oObj.itemnumber + "' data-materials='" + oObj.materials.escapeHtml() + "'></input>"; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/recalls.js b/koha-tmpl/intranet-tmpl/prog/js/recalls.js >new file mode 100644 >index 0000000000..c45a6c8f19 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/js/recalls.js >@@ -0,0 +1,175 @@ >+$(document).ready(function() { >+ >+ $(".cancel_recall").click(function(e){ >+ if (confirmDelete(__("Are you sure you want to remove this recall?"))){ >+ var $self = $(this); >+ var $recall_id = $(this).data('id'); >+ var $action = $(this).data('action'); >+ var ajaxData = { >+ 'recall_id': $recall_id, >+ 'action' : $action, >+ }; >+ >+ $.ajax({ >+ url: '/cgi-bin/koha/svc/recall', >+ type: 'POST', >+ dataType: 'json', >+ data: ajaxData, >+ }) >+ .done(function(data) { >+ var message = ""; >+ if(data.success == 0) { >+ message = __("The recall may have already been cancelled. Please refresh the page."); >+ } else { >+ message = __("Cancelled"); >+ } >+ $self.parent().parent().parent().parent().html(message); >+ }); >+ } >+ }); >+ >+ $(".expire_recall").click(function(e){ >+ if (confirmDelete(__("Are you sure you want to expire this recall?"))){ >+ var $self = $(this); >+ var $recall_id = $(this).data('id'); >+ var $action = $(this).data('action'); >+ var ajaxData = { >+ 'recall_id': $recall_id, >+ 'action' : $action, >+ }; >+ >+ $.ajax({ >+ url: '/cgi-bin/koha/svc/recall', >+ type: 'POST', >+ dataType: 'json', >+ data: ajaxData, >+ }) >+ .done(function(data) { >+ var message = ""; >+ if(data.success == 0) { >+ message = __("The recall may have already been expired. Please refresh the page."); >+ } else { >+ message = __("Expired"); >+ } >+ $self.parent().parent().parent().parent().html(message); >+ }); >+ } >+ }); >+ >+ $(".revert_recall").click(function(e){ >+ if (confirmDelete(__("Are you sure you want to revert the waiting status of this recall?"))){ >+ var $self = $(this); >+ var $recall_id = $(this).data('id'); >+ var $action = $(this).data('action'); >+ var ajaxData = { >+ 'recall_id': $recall_id, >+ 'action' : $action, >+ }; >+ >+ $.ajax({ >+ url: '/cgi-bin/koha/svc/recall', >+ type: 'POST', >+ dataType: 'json', >+ data: ajaxData, >+ }) >+ .done(function(data) { >+ var message = ""; >+ if(data.success == 0) { >+ message = __("The recall waiting status may have already been reverted. Please refresh the page."); >+ } else { >+ message = __("Status updated"); >+ } >+ $self.parent().parent().parent().parent().html(message); >+ }); >+ } >+ }); >+ >+ $(".overdue_recall").click(function(e){ >+ if (confirmDelete(__("Are you sure you want to mark this recall as overdue?"))){ >+ var $self = $(this); >+ var $recall_id = $(this).data('id'); >+ var $action = $(this).data('action'); >+ var ajaxData = { >+ 'recall_id': $recall_id, >+ 'action' : $action, >+ }; >+ >+ $.ajax({ >+ url: '/cgi-bin/koha/svc/recall', >+ type: 'POST', >+ dataType: 'json', >+ data: ajaxData, >+ }) >+ .done(function(data) { >+ var message = ""; >+ if(data.success == 0) { >+ message = __("The recall may have already been marked as overdue. Please refresh the page."); >+ } else { >+ message = __("Marked overdue"); >+ } >+ $self.parent().parent().parent().parent().html(message); >+ }); >+ } >+ }); >+ >+ $(".transit_recall").click(function(e){ >+ if (confirmDelete(__("Are you sure you want to remove this recall and return the item to it's home library?"))){ >+ var $self = $(this); >+ var $recall_id = $(this).data('id'); >+ var $action = $(this).data('action'); >+ var ajaxData = { >+ 'recall_id': $recall_id, >+ 'action' : $action, >+ }; >+ >+ $.ajax({ >+ url: '/cgi-bin/koha/svc/recall', >+ type: 'POST', >+ dataType: 'json', >+ data: ajaxData, >+ }) >+ .done(function(data) { >+ var message = ""; >+ if(data.success == 0) { >+ message = __("The recall may have already been removed. Please refresh the page."); >+ } else { >+ message = __("Cancelled"); >+ } >+ $self.parent().parent().parent().parent().html(message); >+ }); >+ } >+ }); >+ >+ $("#recalls-table").dataTable($.extend(true, {}, dataTablesDefaults, { >+ "aoColumnDefs": [ >+ { 'bSortable': false, 'aTargets': [ 'nosort' ] }, >+ { "sType": "title-string", "aTargets" : [ "title-string" ] }, >+ { "sType": "anti-the", "aTargets": [ "anti-the" ] } >+ ], >+ "sPaginationType": "full_numbers" >+ })); >+ >+ $("#cancel_selected").click(function(e){ >+ if ($("input[name='recall_ids']:checked").length > 0){ >+ return confirmDelete(__("Are you sure you want to remove the selected recall(s)?")); >+ } else { >+ alert(__("Please make a selection.")); >+ } >+ }); >+ >+ $("#select_all").click(function(){ >+ if ($("#select_all").prop("checked")){ >+ $("input[name='recall_ids']").prop("checked", true); >+ } else { >+ $("input[name='recall_ids']").prop("checked", false); >+ } >+ }); >+ >+ $("#hide_old").click(function(){ >+ if ($("#hide_old").prop("checked")){ >+ $(".old").show(); >+ } else { >+ $(".old").hide(); >+ } >+ }); >+}); >diff --git a/members/moremember.pl b/members/moremember.pl >index 8f6e959850..f4cd878801 100755 >--- a/members/moremember.pl >+++ b/members/moremember.pl >@@ -210,6 +210,8 @@ $template->param( > relatives_borrowernumbers => \@relatives, > logged_in_user => $logged_in_user, > files => Koha::Patron::Files->new( borrowernumber => $borrowernumber ) ->GetFilesInfo(), >+ recalls => $patron->recalls, >+ specific_patron => 1, > ); > > output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/members/recallshistory.pl b/members/recallshistory.pl >new file mode 100755 >index 0000000000..175f15945e >--- /dev/null >+++ b/members/recallshistory.pl >@@ -0,0 +1,47 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Auth; >+use C4::Output; >+ >+my $input = CGI->new; >+my ($template, $loggedinuser, $cookie)= get_template_and_user( >+ { >+ template_name => "members/recallshistory.tt", >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { recalls => 1 }, >+ debug => 1, >+ } >+); >+ >+my $borrowernumber = $input->param('borrowernumber'); >+my $recalls = Koha::Recalls->search({ borrowernumber => $borrowernumber }, { order_by => { '-desc' => 'recalldate' } }); >+my $patron = Koha::Patrons->find( $borrowernumber ); >+ >+$template->param( >+ patron => $patron, >+ recalls => $recalls, >+ recallsview => 1, >+ specific_patron => 1, >+); >+ >+output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/recalls/recall_pickup_slip.pl b/recalls/recall_pickup_slip.pl >new file mode 100755 >index 0000000000..7a130871f2 >--- /dev/null >+++ b/recalls/recall_pickup_slip.pl >@@ -0,0 +1,74 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Context; >+use C4::Output; >+use C4::Auth; >+ >+my $input = new CGI; >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user( >+ { >+ template_name => "circ/printslip.tt", >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { circulate => "circulate_remaining_permissions" }, >+ } >+); >+ >+my $recallid = $input->param('recall_id'); >+my $recall = Koha::Recalls->find($recallid); >+ >+my $itemnumber; >+if ( $recall->itemnumber ){ >+ $itemnumber = $recall->itemnumber; >+} else { >+ $itemnumber = $recall->checkout->itemnumber; >+} >+ >+# Print slip to inform library staff of details of recall requester, so the item can be put aside for requester >+my $letter = C4::Letters::GetPreparedLetter( >+ module => 'circulation', >+ letter_code => 'RECALL_REQUESTER_DET', >+ message_transport_type => 'print', >+ tables => { >+ 'branches' => $recall->branchcode, >+ 'borrowers' => $recall->borrowernumber, >+ 'biblio' => $recall->biblionumber, >+ 'items' => $itemnumber, >+ 'recalls' => $recall->recall_id, >+ } >+); >+ >+my ($slip, $is_html); >+if ($letter) { >+ $slip = $letter->{content}; >+ $is_html = $letter->{is_html}; >+} >+ >+$template->param( >+ slip => $slip, >+ plain => !$is_html, >+ caller => 'recall', >+); >+ >+output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/recalls/recalls_old_queue.pl b/recalls/recalls_old_queue.pl >new file mode 100755 >index 0000000000..161dcd41a1 >--- /dev/null >+++ b/recalls/recalls_old_queue.pl >@@ -0,0 +1,47 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Auth; >+use C4::Output; >+use Koha::BiblioFrameworks; >+ >+my $query = new CGI; >+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( >+ { >+ template_name => "recalls/recalls_old_queue.tt", >+ query => $query, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { recalls => "manage_recalls" }, >+ debug => 1, >+ } >+); >+ >+my $recalls = Koha::Recalls->search({ old => 1 }); >+$template->param( >+ recalls => $recalls, >+ viewing_old => 1 >+); >+ >+# Checking if there is a Fast Cataloging Framework >+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' ); >+ >+# writing the template >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/recalls/recalls_overdue.pl b/recalls/recalls_overdue.pl >new file mode 100755 >index 0000000000..91c1e6973d >--- /dev/null >+++ b/recalls/recalls_overdue.pl >@@ -0,0 +1,61 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Auth; >+use C4::Output; >+use Koha::BiblioFrameworks; >+use Koha::DateUtils; >+ >+my $query = new CGI; >+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( >+ { >+ template_name => "recalls/recalls_overdue.tt", >+ query => $query, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { recalls => "manage_recalls" }, >+ debug => 1, >+ } >+); >+ >+my $op = $query->param('op') || 'list'; >+my @recall_ids = $query->multi_param('recall_ids'); >+ >+if ( $op eq 'cancel_multiple_recalls' ) { >+ foreach my $id ( @recall_ids ) { >+ Koha::Recalls->find( $id )->set_cancelled; >+ } >+ $op = 'list' >+} >+ >+if ( $op eq 'list' ) { >+ my $recalls = Koha::Recalls->search({ status => 'O' }); >+ # will be set as Overdue by the misc/cronjobs/recall/overdue_recalls.pl cronjob >+ $template->param( >+ recalls => $recalls, >+ checkboxes => 1, >+ ); >+} >+ >+# Checking if there is a Fast Cataloging Framework >+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' ); >+ >+# writing the template >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/recalls/recalls_queue.pl b/recalls/recalls_queue.pl >new file mode 100755 >index 0000000000..0d820592a0 >--- /dev/null >+++ b/recalls/recalls_queue.pl >@@ -0,0 +1,57 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Auth; >+use C4::Output; >+use Koha::BiblioFrameworks; >+ >+my $query = new CGI; >+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( >+ { >+ template_name => "recalls/recalls_queue.tt", >+ query => $query, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { recalls => 'manage_recalls' }, >+ debug => 1, >+ } >+); >+ >+my $op = $query->param('op') || 'list'; >+my @recall_ids = $query->multi_param('recall_ids'); >+if ( $op eq 'cancel_multiple_recalls' ) { >+ foreach my $id ( @recall_ids ) { >+ Koha::Recalls->find( $id )->set_cancelled; >+ } >+ $op = 'list' >+} >+elsif ( $op eq 'list' ) { >+ my $recalls = Koha::Recalls->search({ old => undef }); >+ $template->param( >+ recalls => $recalls, >+ checkboxes => 1, >+ ); >+} >+ >+# Checking if there is a Fast Cataloging Framework >+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' ); >+ >+# writing the template >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/recalls/recalls_to_pull.pl b/recalls/recalls_to_pull.pl >new file mode 100755 >index 0000000000..8582de1460 >--- /dev/null >+++ b/recalls/recalls_to_pull.pl >@@ -0,0 +1,126 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Auth; >+use C4::Output; >+use Koha::BiblioFrameworks; >+ >+my $query = new CGI; >+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( >+ { >+ template_name => "recalls/recalls_to_pull.tt", >+ query => $query, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { recalls => 'manage_recalls' }, >+ debug => 1, >+ } >+); >+ >+my $op = $query->param('op') || 'list'; >+my $recall_id = $query->param('recall_id'); >+if ( $op eq 'cancel' ) { >+ my $recall = Koha::Recalls->find( $recall_id ); >+ if ( $recall->in_transit ) { >+ C4::Items::ModItemTransfer( $recall->item->itemnumber, $recall->item->holdingbranch, $recall->item->homebranch, 'CancelRecall' ); >+ } >+ $recall->set_cancelled; >+ $op = 'list'; >+} >+ >+if ( $op eq 'list' ) { >+ my @recalls = Koha::Recalls->search({ status => [ 'R','O','T' ] }); >+ my @pull_list; >+ my %seen_bib; >+ foreach my $recall ( @recalls ) { >+ if ( $seen_bib{$recall->biblionumber} ){ >+ # we've already looked at the recalls on this biblio >+ next; >+ } else { >+ # this is an unseen biblio >+ $seen_bib{$recall->biblionumber}++; >+ >+ # get recall data about this biblio >+ my @this_bib_recalls = Koha::Recalls->search({ biblionumber => $recall->biblionumber, status => [ 'R','O','T' ] }, { order_by => { -asc => 'recalldate' } }); >+ my $recalls_count = scalar @this_bib_recalls; >+ my @unique_patrons = do { my %seen; grep { !$seen{$_->borrowernumber}++ } @this_bib_recalls }; >+ my $patrons_count = scalar @unique_patrons; >+ my $first_recall = $this_bib_recalls[0]; >+ >+ my $items_count = 0; >+ my @callnumbers; >+ my @copynumbers; >+ my @enumchrons; >+ my @itemtypes; >+ my @locations; >+ my @libraries; >+ >+ my @items = Koha::Items->search({ biblionumber => $recall->biblionumber }); >+ foreach my $item ( @items ) { >+ if ( $item->can_be_waiting_recall and !$item->checkout ) { >+ # if item can be pulled to fulfill recall, collect item data >+ $items_count++; >+ push( @callnumbers, $item->itemcallnumber ) if ( $item->itemcallnumber ); >+ push( @copynumbers, $item->copynumber ) if ( $item->copynumber ); >+ push( @enumchrons, $item->enumchron ) if ( $item->enumchron ); >+ push( @itemtypes, $item->effective_itemtype ) if ( $item->effective_itemtype ); >+ push( @locations, $item->location ) if ( $item->location ); >+ push( @libraries, $item->holdingbranch ) if ( $item->holdingbranch ); >+ } >+ } >+ >+ if ( $items_count > 0 ) { >+ # don't push data if there are no items available for this recall >+ >+ # get unique values >+ my @unique_callnumbers = do { my %seen; grep { !$seen{$_}++ } @callnumbers }; >+ my @unique_copynumbers = do { my %seen; grep { !$seen{$_}++ } @copynumbers }; >+ my @unique_enumchrons = do { my %seen; grep { !$seen{$_}++ } @enumchrons }; >+ my @unique_itemtypes = do { my %seen; grep { !$seen{$_}++ } @itemtypes }; >+ my @unique_locations = do { my %seen; grep { !$seen{$_}++ } @locations }; >+ my @unique_libraries = do { my %seen; grep { !$seen{$_}++ } @libraries }; >+ >+ push( @pull_list, { >+ biblio => $recall->biblio, >+ items_count => $items_count, >+ recalls_count => $recalls_count, >+ patrons_count => $patrons_count, >+ pull_count => $items_count <= $recalls_count ? $items_count : $recalls_count, >+ first_recall => $first_recall, >+ callnumbers => \@unique_callnumbers, >+ copynumbers => \@unique_copynumbers, >+ enumchrons => \@unique_enumchrons, >+ itemtypes => \@unique_itemtypes, >+ locations => \@unique_locations, >+ libraries => \@unique_libraries, >+ }); >+ } >+ } >+ } >+ $template->param( >+ recalls => \@pull_list, >+ ); >+} >+ >+# Checking if there is a Fast Cataloging Framework >+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' ); >+ >+# writing the template >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/recalls/recalls_waiting.pl b/recalls/recalls_waiting.pl >new file mode 100755 >index 0000000000..4026fee1dc >--- /dev/null >+++ b/recalls/recalls_waiting.pl >@@ -0,0 +1,76 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Auth; >+use C4::Output; >+use Koha::Recalls; >+use Koha::BiblioFrameworks; >+use Koha::DateUtils; >+use Koha::Patrons; >+ >+my $query = new CGI; >+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( >+ { >+ template_name => "recalls/recalls_waiting.tt", >+ query => $query, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { recalls => "manage_recalls" }, >+ debug => 1, >+ } >+); >+ >+my $op = $query->param('op') || 'list'; >+ >+if ( $op eq 'modify' ) { >+ my $expire = $query->param('expire') || ''; >+ my $revert = $query->param('revert') || ''; >+ my $recall_id = $query->param('recall_id'); >+ if ( $expire ) { >+ Koha::Recalls->find( $recall_id )->set_expired({ interface => 'INTRANET' }); >+ } elsif ( $revert ) { >+ Koha::Recalls->find( $recall_id )->revert_waiting; >+ } >+ $op = 'list'; >+} >+ >+if ( $op eq 'list' ) { >+ my @recalls = Koha::Recalls->search({ status => 'W' }); >+ my $borrower = Koha::Patrons->find( $loggedinuser ); >+ my @over; >+ my $maxdelay = C4::Context->preference('RecallsMaxPickUpDelay') || 7; >+ my $today = dt_from_string(); >+ foreach my $r ( @recalls ){ >+ my $lastwaitingday = dt_from_string( $r->waitingdate )->add( days => $maxdelay ); >+ if ( $today > $lastwaitingday ){ >+ push @over, $r; >+ } >+ } >+ $template->param( >+ recalls => \@recalls, >+ over => \@over, >+ ); >+} >+ >+# Checking if there is a Fast Cataloging Framework >+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' ); >+ >+# writing the template >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/recalls/request.pl b/recalls/request.pl >new file mode 100755 >index 0000000000..59a4b4555b >--- /dev/null >+++ b/recalls/request.pl >@@ -0,0 +1,65 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI qw ( -utf8 ); >+use C4::Auth; >+use C4::Output; >+use C4::Search; >+use Koha::Recalls; >+use Koha::Biblios; >+ >+my $input = CGI->new; >+my ($template, $loggedinuser, $cookie)= get_template_and_user( >+ { >+ template_name => "recalls/request.tt", >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { recalls => "manage_recalls" }, >+ debug => 1, >+ } >+); >+ >+my $op = $input->param('op') || 'list'; >+my @recall_ids = $input->multi_param('recall_ids'); >+my $biblionumber = $input->param('biblionumber'); >+my $recalls = Koha::Recalls->search({ biblionumber => $biblionumber, old => undef }); >+my $biblio = Koha::Biblios->find( $biblionumber ); >+ >+if ( $op eq 'cancel_multiple_recalls' ) { >+ foreach my $id ( @recall_ids ) { >+ Koha::Recalls->find( $id )->set_cancelled; >+ } >+ $op = 'list' >+} >+ >+if ( $op eq 'list' ) { >+ $recalls = Koha::Recalls->search({ biblionumber => $biblionumber, old => undef }); >+ $biblio = Koha::Biblios->find( $biblionumber ); >+} >+ >+$template->param( >+ recalls => $recalls, >+ recallsview => 1, >+ biblio => $biblio, >+ checkboxes => 1, >+ C4::Search::enabled_staff_search_views, >+); >+ >+output_html_with_http_headers $input, $cookie, $template->output; >diff --git a/reserve/request.pl b/reserve/request.pl >index 1751a0aa92..8643a4c75d 100755 >--- a/reserve/request.pl >+++ b/reserve/request.pl >@@ -316,6 +316,9 @@ foreach my $biblionumber (@biblionumbers) { > } > elsif ( $canReserve->{status} eq 'alreadypossession' ) { > $template->param( $canReserve->{status} => 1); >+ } >+ elsif ( $canReserve->{status} eq 'recall' ) { >+ $template->param( $canReserve->{status} => 1 ); > $biblioloopiter{ $canReserve->{status} } = 1; > } > else { >diff --git a/svc/checkouts b/svc/checkouts >index 38c0017e2c..1943ea53b2 100755 >--- a/svc/checkouts >+++ b/svc/checkouts >@@ -210,6 +210,27 @@ while ( my $c = $sth->fetchrow_hashref() ) { > $materials = $descriptions->{lib} // $c->{materials}; > } > my @subtitles = split(/ \| /, $c->{'subtitle'} // '' ); >+ >+ my $item = Koha::Items->find( $c->{itemnumber} ); >+ my $recalled = 0; >+ my $recall = undef; >+ $recall = $item->check_recalls if $item->can_be_waiting_recall; >+ if ( defined $recall ) { >+ if ( $recall->item_level_recall ) { >+ if ( $recall->itemnumber == $c->{itemnumber} ) { >+ # item-level recall on this item >+ $recalled = 1; >+ } else { >+ $recalled = 0; >+ } >+ } else { >+ # biblio-level recall, but don't want to mark recalled if the recall has been allocated a different item >+ if ( !$recall->waiting ) { >+ $recalled = 1; >+ } >+ } >+ } >+ > my $checkout = { > DT_RowId => $c->{itemnumber} . '-' . $c->{borrowernumber}, > title => $c->{title}, >@@ -282,6 +303,7 @@ while ( my $c = $sth->fetchrow_hashref() ) { > cardnumber => $c->{cardnumber}, > }, > issued_today => !$c->{not_issued_today}, >+ recalled => $recalled, > }; > > if ( $c->{not_issued_today} ) { >diff --git a/svc/recall b/svc/recall >new file mode 100755 >index 0000000000..35c24585ff >--- /dev/null >+++ b/svc/recall >@@ -0,0 +1,89 @@ >+#!/usr/bin/perl >+ >+# Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz> >+# >+# 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 CGI; >+use JSON qw(encode_json); >+ >+use C4::Context; >+use C4::Auth qw(check_cookie_auth); >+use C4::Output qw(output_with_http_headers); >+use C4::Circulation qw(AddReturn); >+use Koha::Recalls; >+ >+my $input = new CGI; >+my $json = encode_json({ success => 0 }); >+ >+my ( $auth_status, $sessionID ) = check_cookie_auth( $input->cookie('CGISESSID'), { recall => 'manage_recalls' } ); >+ >+if ( $auth_status ne "ok" ) { >+ print $input->header(-type => 'text/plain', -status => '403 Forbidden'); >+ exit 0; >+} >+ >+my $recall_id = $input->param('recall_id'); >+my $recall = Koha::Recalls->find( $recall_id ); >+unless ( $recall ) { >+ my $json = encode_json({ success => 0 }); >+ output_with_http_headers( $input, undef, $json, "json" ); >+ exit; >+} >+ >+my $op = $input->param('action'); >+ >+if ( $op eq 'cancel' ) { >+ # cancel recall >+ $recall->set_cancelled; >+ if ( $recall->cancelled ){ >+ $json = encode_json({ success => 1 }); >+ } >+ >+} elsif ( $op eq 'expire' ) { >+ # expire recall >+ $recall->set_expired({ interface => 'INTRANET' }); >+ if ( $recall->expired ){ >+ $json = encode_json({ success => 1 }); >+ } >+ >+} elsif ( $op eq 'revert' ) { >+ # revert recall waiting status >+ $recall->revert_waiting; >+ if ( $recall->requested ){ >+ $json = encode_json({ success => 1 }); >+ } >+ >+} elsif ( $op eq 'overdue' ) { >+ # mark recall as overdue >+ $recall->set_overdue({ interface => 'INTRANET' }); >+ if ( $recall->overdue ){ >+ $json = encode_json({ success => 1 }); >+ } >+ >+} elsif ( $op eq 'transit' ) { >+ # cancel recall and return item to home library >+ if ( $recall->in_transit ) { >+ C4::Items::ModItemTransfer( $recall->item->itemnumber, $recall->item->holdingbranch, $recall->item->homebranch, 'CancelRecall' ); >+ } >+ $recall->set_cancelled; >+ if ( $recall->cancelled ){ >+ $json = encode_json({ success => 1 }); >+ } >+} >+ >+output_with_http_headers( $input, undef, $json, "json" ); >diff --git a/tools/letter.pl b/tools/letter.pl >index 20eb74771b..3f55ba75a8 100755 >--- a/tools/letter.pl >+++ b/tools/letter.pl >@@ -248,7 +248,7 @@ sub add_form { > {value => 'items.fine', text => 'items.fine'}, > add_fields('borrowers'); > if ($module eq 'circulation') { >- push @{$field_selection}, add_fields('opac_news'); >+ push @{$field_selection}, add_fields('opac_news', 'recalls'); > > } > >diff --git a/tools/viewlog.pl b/tools/viewlog.pl >index b58dcbacac..f90495a843 100755 >--- a/tools/viewlog.pl >+++ b/tools/viewlog.pl >@@ -186,6 +186,16 @@ if ($do_it) { > } > } > } >+ >+ # get recall information >+ if ( $log->module eq "RECALLS" ) { >+ if ( $log->object ) { >+ my $recall = Koha::Recalls->find( $log->object ); >+ if ( $recall && $output eq 'screen' ) { >+ $result->{recall} = $recall; >+ } >+ } >+ } > push @data, $result; > } > if ( $output eq "screen" ) { >-- >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 19532
:
68569
|
68570
|
68571
|
68572
|
68642
|
68643
|
68644
|
68645
|
68653
|
69100
|
69102
|
69147
|
69148
|
69149
|
69170
|
69172
|
69221
|
69222
|
69223
|
69322
|
69353
|
69354
|
69405
|
69409
|
69410
|
69411
|
69841
|
69872
|
69873
|
69874
|
69875
|
69876
|
69877
|
69878
|
69879
|
69880
|
69881
|
69882
|
69883
|
69884
|
69885
|
69886
|
69887
|
69888
|
69889
|
69890
|
69986
|
70093
|
71409
|
71574
|
71575
|
71576
|
71577
|
71578
|
71579
|
71580
|
71581
|
71582
|
71583
|
71584
|
71585
|
71586
|
71587
|
71588
|
71589
|
71590
|
71591
|
71592
|
72244
|
72311
|
72312
|
72313
|
72314
|
72315
|
72316
|
72317
|
72318
|
72319
|
72320
|
72321
|
72322
|
72323
|
72324
|
72325
|
72326
|
72327
|
72328
|
72329
|
72330
|
72331
|
72332
|
72333
|
72334
|
72335
|
72336
|
72337
|
72338
|
72527
|
76817
|
76818
|
76819
|
76820
|
76821
|
76822
|
76823
|
76824
|
76825
|
76826
|
76827
|
76828
|
76829
|
76830
|
76831
|
76832
|
76833
|
76834
|
76835
|
76836
|
76837
|
76838
|
76839
|
76840
|
76841
|
76842
|
76843
|
76844
|
76845
|
76846
|
76847
|
77177
|
77178
|
77179
|
78755
|
78757
|
78759
|
78761
|
78763
|
78765
|
78766
|
78768
|
78770
|
78772
|
78773
|
78774
|
78775
|
78776
|
78777
|
78778
|
78780
|
78782
|
78785
|
78787
|
78789
|
78790
|
78792
|
78794
|
78797
|
78800
|
78801
|
78802
|
78803
|
78804
|
78805
|
78806
|
78807
|
78808
|
80763
|
80764
|
80765
|
80766
|
80767
|
80768
|
80769
|
80770
|
80771
|
80772
|
80773
|
80774
|
80775
|
80776
|
80777
|
80778
|
80779
|
80780
|
80781
|
80782
|
80783
|
80784
|
80785
|
80786
|
80787
|
80788
|
80789
|
80793
|
80878
|
81204
|
81205
|
81206
|
81207
|
81208
|
81209
|
81210
|
81211
|
81212
|
81213
|
81214
|
81215
|
81216
|
81217
|
81218
|
81219
|
81220
|
81221
|
81222
|
81223
|
81224
|
81225
|
81226
|
81227
|
81228
|
81229
|
81230
|
81231
|
81232
|
81233
|
81234
|
81235
|
81236
|
81237
|
81238
|
81239
|
81240
|
81241
|
81242
|
81243
|
81244
|
81245
|
81246
|
81247
|
81547
|
81548
|
81549
|
81550
|
81551
|
81552
|
81553
|
81554
|
81555
|
81556
|
81557
|
81558
|
81559
|
81560
|
81561
|
81562
|
81563
|
81564
|
81565
|
81566
|
81567
|
81568
|
81569
|
81583
|
81584
|
81585
|
81586
|
81587
|
81588
|
81595
|
81618
|
81652
|
81653
|
81654
|
81655
|
81656
|
81657
|
81658
|
81659
|
81660
|
81661
|
81662
|
81663
|
81664
|
81665
|
81666
|
81667
|
81668
|
81669
|
81670
|
81671
|
81672
|
81673
|
81674
|
81675
|
81676
|
81677
|
81678
|
81679
|
81680
|
81681
|
81682
|
81683
|
103887
|
103888
|
103890
|
103899
|
103900
|
103901
|
103999
|
104000
|
104001
|
104002
|
104005
|
104006
|
104007
|
104066
|
104067
|
104068
|
104069
|
104070
|
104071
|
104246
|
104247
|
104248
|
104249
|
104250
|
104322
|
104323
|
104324
|
104325
|
104326
|
104327
|
104328
|
104329
|
104330
|
104331
|
104332
|
104333
|
104334
|
104335
|
104336
|
104391
|
104392
|
104393
|
104394
|
104395
|
104396
|
104397
|
104398
|
104474
|
104475
|
104476
|
104477
|
104478
|
104479
|
104480
|
104481
|
104545
|
104546
|
104547
|
104548
|
104549
|
104550
|
104551
|
104552
|
104646
|
104647
|
104648
|
104649
|
104650
|
104651
|
104652
|
104653
|
104722
|
104723
|
104724
|
104725
|
104726
|
104727
|
104728
|
104729
|
104806
|
104807
|
104808
|
104809
|
104810
|
104811
|
104812
|
104813
|
104814
|
104815
|
104816
|
104817
|
104818
|
104819
|
104820
|
104821
|
104863
|
104864
|
104865
|
104866
|
104867
|
104868
|
104869
|
104870
|
104902
|
104903
|
104904
|
104905
|
104906
|
104907
|
104908
|
104909
|
104910
|
104913
|
104914
|
104915
|
104916
|
104917
|
104918
|
104919
|
104920
|
104988
|
104989
|
104990
|
104991
|
104992
|
106268
|
106269
|
106371
|
106372
|
106373
|
106374
|
106375
|
106376
|
106377
|
106378
|
106810
|
106811
|
106812
|
106813
|
106814
|
106815
|
106816
|
106817
|
106857
|
107198
|
107199
|
107200
|
107201
|
107202
|
107203
|
107204
|
107205
|
107807
|
107808
|
107809
|
107810
|
107811
|
107812
|
107813
|
107814
|
107918
|
107919
|
107920
|
107921
|
107922
|
107923
|
107924
|
107925
|
108222
|
108223
|
108224
|
108225
|
108226
|
108227
|
108228
|
108229
|
108980
|
108981
|
108982
|
109306
|
109307
|
109308
|
109309
|
109310
|
109311
|
109312
|
109313
|
109314
|
109315
|
109316
|
109317
|
109318
|
109463
|
109464
|
109465
|
109466
|
109467
|
109468
|
109469
|
109775
|
109776
|
109777
|
109778
|
109779
|
109780
|
109781
|
109782
|
109783
|
109784
|
109785
|
111199
|
111200
|
111201
|
111202
|
111203
|
111204
|
111205
|
111206
|
112316
|
112317
|
112321
|
112322
|
112323
|
112324
|
112325
|
112326
|
112346
|
112472
|
112491
|
112540
|
112612
|
112613
|
112614
|
112615
|
112616
|
112617
|
112618
|
112619
|
112620
|
112621
|
112622
|
113195
|
113196
|
113197
|
113198
|
113199
|
113200
|
113201
|
113202
|
113203
|
113204
|
113205
|
113286
|
113287
|
113288
|
113289
|
113290
|
113291
|
113292
|
113293
|
113294
|
113295
|
113296
|
113297
|
113298
|
113335
|
113351
|
113352
|
113353
|
113354
|
113355
|
113356
|
113357
|
113358
|
113359
|
113361
|
113362
|
113363
|
113364
|
113365
|
113430
|
113431
|
113432
|
113433
|
113434
|
113435
|
113436
|
113437
|
113438
|
113439
|
113440
|
113441
|
113442
|
113443
|
113444
|
113445
|
116121
|
116122
|
116123
|
116124
|
116125
|
116126
|
116127
|
116128
|
116129
|
116130
|
116131
|
116132
|
116133
|
116134
|
118267
|
118268
|
118269
|
118270
|
118271
|
118272
|
118273
|
118274
|
118275
|
118276
|
118277
|
118278
|
118279
|
118280
|
122993
|
122994
|
122995
|
122996
|
122997
|
122998
|
122999
|
123000
|
123001
|
123002
|
123003
|
123004
|
123005
|
126244
|
126245
|
126246
|
126247
|
126248
|
126249
|
126250
|
126251
|
126252
|
126253
|
126254
|
126255
|
126256
|
126257
|
126453
|
126454
|
126455
|
126456
|
126457
|
126458
|
126459
|
126460
|
126469
|
126470
|
126565
|
126566
|
126568
|
126569
|
126570
|
126571
|
126572
|
126573
|
126574
|
126575
|
126576
|
126577
|
126578
|
126579
|
126580
|
129305
|
129306
|
129307
|
129308
|
129309
|
129310
|
129311
|
129312
|
129313
|
129314
|
129315
|
129316
|
129317
|
129318
|
129319
|
130641
|
130642
|
130643
|
130644
|
130645
|
130646
|
130647
|
130648
|
130649
|
130650
|
130651
|
130652
|
130653
|
130654
|
130655
|
130656
|
131108
|
131156
|
131157
|
131158
|
131159
|
131160
|
131193
|
131213
|
131257
|
131260
|
131261
|
131262
|
131263
|
131264
|
131265
|
131266
|
131267
|
131268
|
131269
|
131270
|
131271
|
131272
|
131273
|
131274
|
131275
|
131276
|
131277
|
131278
|
131279
|
131280
|
131281
|
131282
|
131330
|
131629
|
131630
|
131631
|
131664
|
131665
|
131666
|
131701
|
132332