|
Lines 341-359
sub CanBookBeReserved{
Link Here
|
| 341 |
return { status =>'alreadypossession' }; |
341 |
return { status =>'alreadypossession' }; |
| 342 |
} |
342 |
} |
| 343 |
|
343 |
|
|
|
344 |
my @circulation_rules; |
| 345 |
|
| 344 |
if ( $params->{itemtype} ) { |
346 |
if ( $params->{itemtype} ) { |
| 345 |
|
347 |
|
| 346 |
# biblio-level, item type-contrained |
348 |
# biblio-level, item type-contrained |
| 347 |
my $patron = Koha::Patrons->find($borrowernumber); |
349 |
my $patron = Koha::Patrons->find($borrowernumber); |
| 348 |
my $reservesallowed = Koha::CirculationRules->get_effective_rule( |
350 |
my $reservesallowed_rule = Koha::CirculationRules->get_effective_rule( |
| 349 |
{ |
351 |
{ |
| 350 |
itemtype => $params->{itemtype}, |
352 |
itemtype => $params->{itemtype}, |
| 351 |
categorycode => $patron->categorycode, |
353 |
categorycode => $patron->categorycode, |
| 352 |
branchcode => $pickup_branchcode, |
354 |
branchcode => $pickup_branchcode, |
| 353 |
rule_name => 'reservesallowed', |
355 |
rule_name => 'reservesallowed', |
| 354 |
} |
356 |
} |
| 355 |
)->rule_value; |
357 |
); |
|
|
358 |
push @circulation_rules, $reservesallowed_rule if $reservesallowed_rule; |
| 356 |
|
359 |
|
|
|
360 |
my $reservesallowed = $reservesallowed_rule ? $reservesallowed_rule->rule_value : undef; |
| 357 |
$reservesallowed = ( $reservesallowed eq '' ) ? undef : $reservesallowed; |
361 |
$reservesallowed = ( $reservesallowed eq '' ) ? undef : $reservesallowed; |
| 358 |
|
362 |
|
| 359 |
my $count = $patron->holds->search( |
363 |
my $count = $patron->holds->search( |
|
Lines 368-374
sub CanBookBeReserved{
Link Here
|
| 368 |
} |
372 |
} |
| 369 |
)->count; |
373 |
)->count; |
| 370 |
|
374 |
|
| 371 |
return { status => '' } |
375 |
return { status => '', circulation_rules => \@circulation_rules } |
| 372 |
if defined $reservesallowed and $reservesallowed < $count + 1; |
376 |
if defined $reservesallowed and $reservesallowed < $count + 1; |
| 373 |
} |
377 |
} |
| 374 |
|
378 |
|
|
Lines 386-421
sub CanBookBeReserved{
Link Here
|
| 386 |
$items = Koha::Items->search({ biblionumber => $biblionumber}); |
390 |
$items = Koha::Items->search({ biblionumber => $biblionumber}); |
| 387 |
} |
391 |
} |
| 388 |
|
392 |
|
| 389 |
my $canReserve = { status => '' }; |
393 |
my $response = { status => '', item_responses => [] }; |
| 390 |
my $patron = Koha::Patrons->find( $borrowernumber ); |
394 |
my $patron = Koha::Patrons->find( $borrowernumber ); |
| 391 |
while ( my $item = $items->next ) { |
395 |
while ( my $item = $items->next ) { |
| 392 |
$canReserve = CanItemBeReserved( $patron, $item, $pickup_branchcode, $params ); |
396 |
my $itemResponse = CanItemBeReserved( $patron, $item, $pickup_branchcode, $params ); |
| 393 |
return { status => 'OK' } if $canReserve->{status} eq 'OK'; |
397 |
push @{ $response->{item_responses} }, { %$itemResponse, item => $item }; |
|
|
398 |
|
| 399 |
if ($itemResponse->{status} eq 'OK') { |
| 400 |
$response->{status} = 'OK'; |
| 401 |
|
| 402 |
return $response; |
| 403 |
} |
| 394 |
} |
404 |
} |
| 395 |
return $canReserve; |
405 |
|
|
|
406 |
return $response; |
| 396 |
} |
407 |
} |
| 397 |
|
408 |
|
| 398 |
=head2 CanItemBeReserved |
409 |
=head2 CanItemBeReserved |
| 399 |
|
410 |
|
| 400 |
$canReserve = &CanItemBeReserved($patron, $item, $branchcode, $params) |
411 |
$canReserve = CanItemBeReserved($patron, $item, $branchcode, $params) |
| 401 |
if ($canReserve->{status} eq 'OK') { #We can reserve this Item! } |
412 |
if ($canReserve->{status} eq 'OK') { #We can reserve this Item! } |
| 402 |
|
413 |
|
| 403 |
current params are: |
414 |
Current params are: |
| 404 |
'ignore_hold_counts' - we use this routine to check if an item can fill a hold - on this case we |
415 |
|
| 405 |
should not check if there are too many holds as we only care about reservability |
416 |
=over |
| 406 |
|
417 |
|
| 407 |
@RETURNS { status => OK }, if the Item can be reserved. |
418 |
=item * C<ignore_hold_counts> |
| 408 |
{ status => ageRestricted }, if the Item is age restricted for this borrower. |
419 |
|
| 409 |
{ status => damaged }, if the Item is damaged. |
420 |
we use this routine to check if an item can |
| 410 |
{ status => cannotReserveFromOtherBranches }, if syspref 'canreservefromotherbranches' is OK. |
421 |
fill a hold - on this case we should not check if there are too many holds as |
| 411 |
{ status => branchNotInHoldGroup }, if borrower home library is not in hold group, and holds are only allowed from hold groups. |
422 |
we only care about reservability |
| 412 |
{ status => tooManyReserves, limit => $limit }, if the borrower has exceeded their maximum reserve amount. |
423 |
|
| 413 |
{ status => notReservable }, if holds on this item are not allowed |
424 |
=back |
| 414 |
{ status => libraryNotFound }, if given branchcode is not an existing library |
425 |
|
| 415 |
{ status => libraryNotPickupLocation }, if given branchcode is not configured to be a pickup location |
426 |
Returns a hashref with the following keys: |
| 416 |
{ status => cannotBeTransferred }, if branch transfer limit applies on given item and branchcode |
427 |
|
| 417 |
{ status => pickupNotInHoldGroup }, pickup location is not in hold group, and pickup locations are only allowed from hold groups. |
428 |
=over |
| 418 |
{ status => recall }, if the borrower has already placed a recall on this item |
429 |
|
|
|
430 |
=item * C<status> |
| 431 |
|
| 432 |
A string that can have the following values: |
| 433 |
|
| 434 |
=over |
| 435 |
|
| 436 |
=item * C<OK> if the item can be reserved |
| 437 |
|
| 438 |
=item * C<ageRestricted> if the item is aged restricted for this borrower |
| 439 |
|
| 440 |
=item * C<damaged> if the item is damaged |
| 441 |
|
| 442 |
=item * C<cannotReserveFromOtherBranches> if syspref |
| 443 |
'canreservefromotherbranches' is OK |
| 444 |
|
| 445 |
=item * C<branchNotInHoldGroup> if borrower home library is not in hold group, |
| 446 |
and holds are only allowed from hold groups. |
| 447 |
|
| 448 |
=item * C<tooManyReserves> if the borrower has exceeded their maximum reserve |
| 449 |
amount. |
| 450 |
|
| 451 |
=item * C<tooManyHoldsForThisRecord> if the borrower has exceeded their maximum |
| 452 |
reserve amount for this biblio record |
| 453 |
|
| 454 |
=item * C<tooManyReservesToday> if the borrower has exceeded their maximum |
| 455 |
reserve amount for today |
| 456 |
|
| 457 |
=item * C<notReservable> if holds on this item are not allowed |
| 458 |
|
| 459 |
=item * C<libraryNotFound> if given branchcode is not an existing library |
| 460 |
|
| 461 |
=item * C<libraryNotPickupLocation> if given branchcode is not configured to be |
| 462 |
a pickup location |
| 463 |
|
| 464 |
=item * C<cannotBeTransferred> if branch transfer limit applies on given item |
| 465 |
and branchcode |
| 466 |
|
| 467 |
=item * C<pickupNotInHoldGroup> if pickup location is not in hold group, and |
| 468 |
pickup locations are only allowed from hold groups. |
| 469 |
|
| 470 |
=item * C<recall> if the borrower has already placed a recall on this item |
| 471 |
|
| 472 |
=back |
| 473 |
|
| 474 |
=item * C<limit> |
| 475 |
|
| 476 |
Only if C<status> is equal to C<tooManyReserves>, C<tooManyHoldsForThisRecord>, |
| 477 |
or C<tooManyReservesToday>. |
| 478 |
|
| 479 |
It contains the number of reserves allowed. |
| 480 |
|
| 481 |
=item * C<circulation_rules> |
| 482 |
|
| 483 |
An arrayref containing all circulations rules (L<Koha::CirculationRule>) that |
| 484 |
have been checked |
| 485 |
|
| 486 |
=back |
| 419 |
|
487 |
|
| 420 |
=cut |
488 |
=cut |
| 421 |
|
489 |
|
|
Lines 423-430
sub CanItemBeReserved {
Link Here
|
| 423 |
my ( $patron, $item, $pickup_branchcode, $params ) = @_; |
491 |
my ( $patron, $item, $pickup_branchcode, $params ) = @_; |
| 424 |
|
492 |
|
| 425 |
my $dbh = C4::Context->dbh; |
493 |
my $dbh = C4::Context->dbh; |
| 426 |
my $ruleitemtype; # itemtype of the matching issuing rule |
|
|
| 427 |
my $allowedreserves = 0; # Total number of holds allowed across all records, default to none |
| 428 |
|
494 |
|
| 429 |
# We check item branch if IndependentBranches is ON |
495 |
# We check item branch if IndependentBranches is ON |
| 430 |
# and canreservefromotherbranches is OFF |
496 |
# and canreservefromotherbranches is OFF |
|
Lines 481-514
sub CanItemBeReserved {
Link Here
|
| 481 |
$reserves_control_branch = $borrower->{branchcode}; |
547 |
$reserves_control_branch = $borrower->{branchcode}; |
| 482 |
} |
548 |
} |
| 483 |
|
549 |
|
| 484 |
# we retrieve rights |
550 |
my @circulation_rules; |
| 485 |
if ( |
|
|
| 486 |
my $reservesallowed = Koha::CirculationRules->get_effective_rule({ |
| 487 |
itemtype => $item->effective_itemtype, |
| 488 |
categorycode => $borrower->{categorycode}, |
| 489 |
branchcode => $reserves_control_branch, |
| 490 |
rule_name => 'reservesallowed', |
| 491 |
}) |
| 492 |
) { |
| 493 |
$ruleitemtype = $reservesallowed->itemtype; |
| 494 |
$allowedreserves = $reservesallowed->rule_value // 0; #undefined is 0, blank is unlimited |
| 495 |
} |
| 496 |
else { |
| 497 |
$ruleitemtype = undef; |
| 498 |
} |
| 499 |
|
551 |
|
| 500 |
my $rights = Koha::CirculationRules->get_effective_rules({ |
552 |
my $holds_per_record_rule = Koha::CirculationRules->get_effective_rule({ |
| 501 |
categorycode => $borrower->{'categorycode'}, |
553 |
categorycode => $borrower->{categorycode}, |
| 502 |
itemtype => $item->effective_itemtype, |
554 |
itemtype => $item->effective_itemtype, |
| 503 |
branchcode => $reserves_control_branch, |
555 |
branchcode => $reserves_control_branch, |
| 504 |
rules => ['holds_per_record','holds_per_day'] |
556 |
rule_name => 'holds_per_record', |
| 505 |
}); |
557 |
}); |
| 506 |
my $holds_per_record = $rights->{holds_per_record} // 1; |
558 |
push @circulation_rules, $holds_per_record_rule if $holds_per_record_rule; |
| 507 |
my $holds_per_day = $rights->{holds_per_day}; |
559 |
|
|
|
560 |
my $holds_per_record = $holds_per_record_rule ? $holds_per_record_rule->rule_value : 1; |
| 508 |
|
561 |
|
| 509 |
if ( defined $holds_per_record && $holds_per_record ne '' ){ |
562 |
if ( defined $holds_per_record && $holds_per_record ne '' ){ |
| 510 |
if ( $holds_per_record == 0 ) { |
563 |
if ( $holds_per_record == 0 ) { |
| 511 |
return { status => "noReservesAllowed" }; |
564 |
return { status => "noReservesAllowed", circulation_rules => \@circulation_rules }; |
| 512 |
} |
565 |
} |
| 513 |
if ( !$params->{ignore_hold_counts} ) { |
566 |
if ( !$params->{ignore_hold_counts} ) { |
| 514 |
my $search_params = { |
567 |
my $search_params = { |
|
Lines 516-539
sub CanItemBeReserved {
Link Here
|
| 516 |
biblionumber => $item->biblionumber, |
569 |
biblionumber => $item->biblionumber, |
| 517 |
}; |
570 |
}; |
| 518 |
my $holds = Koha::Holds->search($search_params); |
571 |
my $holds = Koha::Holds->search($search_params); |
| 519 |
return { status => "tooManyHoldsForThisRecord", limit => $holds_per_record } if $holds->count() >= $holds_per_record; |
572 |
|
|
|
573 |
if ($holds->count() >= $holds_per_record) { |
| 574 |
return { |
| 575 |
status => "tooManyHoldsForThisRecord", |
| 576 |
limit => $holds_per_record, |
| 577 |
circulation_rules => \@circulation_rules, |
| 578 |
}; |
| 579 |
} |
| 520 |
} |
580 |
} |
| 521 |
} |
581 |
} |
| 522 |
|
582 |
|
|
|
583 |
my $holds_per_day_rule = Koha::CirculationRules->get_effective_rule({ |
| 584 |
categorycode => $borrower->{'categorycode'}, |
| 585 |
itemtype => $item->effective_itemtype, |
| 586 |
branchcode => $reserves_control_branch, |
| 587 |
rule_name => 'holds_per_day', |
| 588 |
}); |
| 589 |
push @circulation_rules, $holds_per_day_rule if $holds_per_day_rule; |
| 590 |
|
| 591 |
my $holds_per_day = $holds_per_day_rule ? $holds_per_day_rule->rule_value : undef; |
| 523 |
if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '') |
592 |
if (!$params->{ignore_hold_counts} && defined $holds_per_day && $holds_per_day ne '') |
| 524 |
{ |
593 |
{ |
| 525 |
my $today_holds = Koha::Holds->search({ |
594 |
my $today_holds = Koha::Holds->search({ |
| 526 |
borrowernumber => $patron->borrowernumber, |
595 |
borrowernumber => $patron->borrowernumber, |
| 527 |
reservedate => dt_from_string->date |
596 |
reservedate => dt_from_string->date |
| 528 |
}); |
597 |
}); |
| 529 |
return { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day; |
598 |
|
|
|
599 |
if ($today_holds->count() >= $holds_per_day) { |
| 600 |
return { |
| 601 |
status => 'tooManyReservesToday', |
| 602 |
limit => $holds_per_day, |
| 603 |
circulation_rules => \@circulation_rules, |
| 604 |
}; |
| 605 |
} |
| 606 |
} |
| 607 |
|
| 608 |
my $reservesallowed_rule = Koha::CirculationRules->get_effective_rule({ |
| 609 |
itemtype => $item->effective_itemtype, |
| 610 |
categorycode => $borrower->{categorycode}, |
| 611 |
branchcode => $reserves_control_branch, |
| 612 |
rule_name => 'reservesallowed', |
| 613 |
}); |
| 614 |
push @circulation_rules, $reservesallowed_rule if $reservesallowed_rule; |
| 615 |
|
| 616 |
my $ruleitemtype; # itemtype of the matching issuing rule |
| 617 |
my $allowedreserves = 0; # Total number of holds allowed across all records, default to none |
| 618 |
if ($reservesallowed_rule) { |
| 619 |
$ruleitemtype = $reservesallowed_rule->itemtype; |
| 620 |
$allowedreserves = $reservesallowed_rule->rule_value // 0; #undefined is 0, blank is unlimited |
| 530 |
} |
621 |
} |
| 531 |
|
622 |
|
| 532 |
# we check if it's ok or not |
623 |
# we check if it's ok or not |
| 533 |
if ( defined $allowedreserves && $allowedreserves ne '' ){ |
624 |
if ( defined $allowedreserves && $allowedreserves ne '' ){ |
| 534 |
if( $allowedreserves == 0 ){ |
625 |
if ( $allowedreserves == 0 ) { |
| 535 |
return { status => 'noReservesAllowed' }; |
626 |
return { |
|
|
627 |
status => 'noReservesAllowed', |
| 628 |
circulation_rules => \@circulation_rules, |
| 629 |
}; |
| 536 |
} |
630 |
} |
|
|
631 |
|
| 537 |
if ( !$params->{ignore_hold_counts} ) { |
632 |
if ( !$params->{ignore_hold_counts} ) { |
| 538 |
# we retrieve count |
633 |
# we retrieve count |
| 539 |
my $querycount = q{ |
634 |
my $querycount = q{ |
|
Lines 577-621
sub CanItemBeReserved {
Link Here
|
| 577 |
$reservecount = $rowcount->{count}; |
672 |
$reservecount = $rowcount->{count}; |
| 578 |
} |
673 |
} |
| 579 |
|
674 |
|
| 580 |
return { status => 'tooManyReserves', limit => $allowedreserves } if $reservecount >= $allowedreserves; |
675 |
if ($reservecount >= $allowedreserves) { |
|
|
676 |
return { |
| 677 |
status => 'tooManyReserves', |
| 678 |
limit => $allowedreserves, |
| 679 |
circulation_rules => \@circulation_rules, |
| 680 |
}; |
| 681 |
} |
| 581 |
} |
682 |
} |
| 582 |
} |
683 |
} |
| 583 |
|
684 |
|
| 584 |
# Now we need to check hold limits by patron category |
685 |
# Now we need to check hold limits by patron category |
| 585 |
my $rule = Koha::CirculationRules->get_effective_rule( |
686 |
my $max_holds_rule = Koha::CirculationRules->get_effective_rule( |
| 586 |
{ |
687 |
{ |
| 587 |
categorycode => $patron->categorycode, |
688 |
categorycode => $patron->categorycode, |
| 588 |
branchcode => $reserves_control_branch, |
689 |
branchcode => $reserves_control_branch, |
| 589 |
rule_name => 'max_holds', |
690 |
rule_name => 'max_holds', |
| 590 |
} |
691 |
} |
| 591 |
); |
692 |
); |
| 592 |
if (!$params->{ignore_hold_counts} && $rule && defined( $rule->rule_value ) && $rule->rule_value ne '' ) { |
693 |
push @circulation_rules, $max_holds_rule if $max_holds_rule; |
|
|
694 |
|
| 695 |
if (!$params->{ignore_hold_counts} && $max_holds_rule && defined( $max_holds_rule->rule_value ) && $max_holds_rule->rule_value ne '' ) { |
| 593 |
my $total_holds_count = Koha::Holds->search( |
696 |
my $total_holds_count = Koha::Holds->search( |
| 594 |
{ |
697 |
{ |
| 595 |
borrowernumber => $patron->borrowernumber |
698 |
borrowernumber => $patron->borrowernumber |
| 596 |
} |
699 |
} |
| 597 |
)->count(); |
700 |
)->count(); |
| 598 |
|
701 |
|
| 599 |
return { status => 'tooManyReserves', limit => $rule->rule_value} if $total_holds_count >= $rule->rule_value; |
702 |
if ($total_holds_count >= $max_holds_rule->rule_value) { |
|
|
703 |
return { |
| 704 |
status => 'tooManyReserves', |
| 705 |
limit => $max_holds_rule->rule_value, |
| 706 |
circulation_rules => \@circulation_rules, |
| 707 |
}; |
| 708 |
} |
| 600 |
} |
709 |
} |
| 601 |
|
710 |
|
|
|
711 |
my $holdallowed_rule = Koha::CirculationRules->get_effective_rule({ |
| 712 |
branchcode => $reserves_control_branch, |
| 713 |
itemtype => $item->effective_itemtype, |
| 714 |
rule_name => 'holdallowed', |
| 715 |
}); |
| 716 |
push @circulation_rules, $holdallowed_rule if $holdallowed_rule; |
| 717 |
|
| 602 |
my $branchitemrule = |
718 |
my $branchitemrule = |
| 603 |
C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype ); |
719 |
C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype ); |
| 604 |
|
720 |
|
| 605 |
if ( $branchitemrule->{holdallowed} eq 'not_allowed' ) { |
721 |
if ( $branchitemrule->{holdallowed} eq 'not_allowed' ) { |
| 606 |
return { status => 'notReservable' }; |
722 |
return { status => 'notReservable', circulation_rules => \@circulation_rules }; |
| 607 |
} |
723 |
} |
| 608 |
|
724 |
|
| 609 |
if ( $branchitemrule->{holdallowed} eq 'from_home_library' |
725 |
if ( $branchitemrule->{holdallowed} eq 'from_home_library' |
| 610 |
&& $borrower->{branchcode} ne $item->homebranch ) |
726 |
&& $borrower->{branchcode} ne $item->homebranch ) |
| 611 |
{ |
727 |
{ |
| 612 |
return { status => 'cannotReserveFromOtherBranches' }; |
728 |
return { status => 'cannotReserveFromOtherBranches', circulation_rules => \@circulation_rules }; |
| 613 |
} |
729 |
} |
| 614 |
|
730 |
|
| 615 |
my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} ); |
731 |
my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} ); |
| 616 |
if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') { |
732 |
if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') { |
| 617 |
if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) { |
733 |
if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) { |
| 618 |
return { status => 'branchNotInHoldGroup' }; |
734 |
return { status => 'branchNotInHoldGroup', circulation_rules => \@circulation_rules }; |
| 619 |
} |
735 |
} |
| 620 |
} |
736 |
} |
| 621 |
|
737 |
|
|
Lines 633-647
sub CanItemBeReserved {
Link Here
|
| 633 |
unless ($item->can_be_transferred({ to => $destination })) { |
749 |
unless ($item->can_be_transferred({ to => $destination })) { |
| 634 |
return { status => 'cannotBeTransferred' }; |
750 |
return { status => 'cannotBeTransferred' }; |
| 635 |
} |
751 |
} |
|
|
752 |
|
| 753 |
my $hold_fulfillment_policy_rule = Koha::CirculationRules->get_effective_rule({ |
| 754 |
branchcode => $reserves_control_branch, |
| 755 |
itemtype => $item->effective_itemtype, |
| 756 |
rule_name => 'hold_fulfillment_policy', |
| 757 |
}); |
| 758 |
push @circulation_rules, $hold_fulfillment_policy_rule if $hold_fulfillment_policy_rule; |
| 759 |
|
| 636 |
if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) { |
760 |
if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) { |
| 637 |
return { status => 'pickupNotInHoldGroup' }; |
761 |
return { status => 'pickupNotInHoldGroup', circulation_rules => \@circulation_rules }; |
| 638 |
} |
762 |
} |
| 639 |
if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) { |
763 |
if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) { |
| 640 |
return { status => 'pickupNotInHoldGroup' }; |
764 |
return { status => 'pickupNotInHoldGroup', circulation_rules => \@circulation_rules }; |
| 641 |
} |
765 |
} |
| 642 |
} |
766 |
} |
| 643 |
|
767 |
|
| 644 |
return { status => 'OK' }; |
768 |
return { status => 'OK', circulation_rules => \@circulation_rules }; |
| 645 |
} |
769 |
} |
| 646 |
|
770 |
|
| 647 |
=head2 CanReserveBeCanceledFromOpac |
771 |
=head2 CanReserveBeCanceledFromOpac |