Merge remote-tracking branch 'upstream/24.05.x' into HEAD
This commit is contained in:
commit
17ea7afac8
31
C4/Auth.pm
31
C4/Auth.pm
|
|
@ -82,14 +82,9 @@ BEGIN {
|
|||
get_template_and_user haspermission create_basic_session
|
||||
);
|
||||
|
||||
$ldap = C4::Context->config('useldapserver') || 0;
|
||||
$cas = C4::Context->preference('casAuthentication');
|
||||
$caslogout = C4::Context->preference('casLogout');
|
||||
|
||||
if ($ldap) {
|
||||
require C4::Auth_with_ldap;
|
||||
import C4::Auth_with_ldap qw(checkpw_ldap);
|
||||
}
|
||||
if ($cas) {
|
||||
require C4::Auth_with_cas; # no import
|
||||
import C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url logout_if_required multipleAuth getMultipleAuth);
|
||||
|
|
@ -554,9 +549,9 @@ sub get_template_and_user {
|
|||
my $opac_limit_override = $ENV{'OPAC_LIMIT_OVERRIDE'};
|
||||
my $opac_name = '';
|
||||
if (
|
||||
( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /branch:([\w-]+)/ ) ||
|
||||
( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /branch:([\w-]+)/ ) ||
|
||||
( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /multibranchlimit:(\w+)/ )
|
||||
( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /^branch:([\w-]+)/ ) ||
|
||||
( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /^branch:([\w-]+)/ ) ||
|
||||
( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /^multibranchlimit:(\w+)/ )
|
||||
) {
|
||||
$opac_name = $1; # opac_search_limit is a branch, so we use it.
|
||||
} elsif ( $in->{'query'}->param('multibranchlimit') ) {
|
||||
|
|
@ -1418,6 +1413,11 @@ sub checkauth {
|
|||
my $auth_error = $query->param('auth_error');
|
||||
my $auth_template_name = ( $type eq 'opac' ) ? 'opac-auth.tt' : 'auth.tt';
|
||||
my $template = C4::Templates::gettemplate( $auth_template_name, $type, $query );
|
||||
|
||||
my $borrowernumber = $patron and $patron->borrowernumber;
|
||||
my $anonymous_patron = C4::Context->preference('AnonymousPatron');
|
||||
my $is_anonymous_patron = $patron && ( $patron->borrowernumber eq $anonymous_patron );
|
||||
|
||||
$template->param(
|
||||
login => 1,
|
||||
INPUTS => \@inputs,
|
||||
|
|
@ -1452,6 +1452,7 @@ sub checkauth {
|
|||
opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'},
|
||||
too_many_login_attempts => ( $patron and $patron->account_locked ),
|
||||
password_has_expired => ( $patron and $patron->password_expired ),
|
||||
is_anonymous_patron => ( $is_anonymous_patron ),
|
||||
auth_error => $auth_error,
|
||||
);
|
||||
|
||||
|
|
@ -1981,20 +1982,24 @@ sub checkpw {
|
|||
my $shib = C4::Context->config('useshibboleth') && shib_ok();
|
||||
my $shib_login = $shib ? get_login_shib() : undef;
|
||||
|
||||
my $anonymous_patron = C4::Context->preference('AnonymousPatron');
|
||||
|
||||
my @return;
|
||||
my $check_internal_as_fallback = 0;
|
||||
my $passwd_ok = 0;
|
||||
my $patron;
|
||||
|
||||
|
||||
# Note: checkpw_* routines returns:
|
||||
# 1 if auth is ok
|
||||
# 0 if auth is nok
|
||||
# -1 if user bind failed (LDAP only)
|
||||
|
||||
$ldap = C4::Context->config('useldapserver') || 0;
|
||||
if ( $ldap && defined($password) ) {
|
||||
my ( $retval, $retcard, $retuserid );
|
||||
( $retval, $retcard, $retuserid, $patron ) = checkpw_ldap(@_); # EXTERNAL AUTH
|
||||
require C4::Auth_with_ldap;
|
||||
import C4::Auth_with_ldap qw(checkpw_ldap);
|
||||
|
||||
( $retval, $retcard, $retuserid, $patron ) = C4::Auth_with_ldap::checkpw_ldap(@_); # EXTERNAL AUTH
|
||||
if ( $retval == 1 ) {
|
||||
@return = ( $retval, $retcard, $retuserid, $patron );
|
||||
$passwd_ok = 1;
|
||||
|
|
@ -2058,7 +2063,9 @@ sub checkpw {
|
|||
@return = ();
|
||||
} elsif ($passwd_ok) {
|
||||
$patron->update( { login_attempts => 0 } );
|
||||
if ( $patron->password_expired ) {
|
||||
if ( defined($anonymous_patron) && ($patron->borrowernumber eq $anonymous_patron) ) {
|
||||
@return = ( -3, $patron );
|
||||
} elsif ( $patron->password_expired ) {
|
||||
@return = ( -2, $patron );
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ sub checkpw_ldap {
|
|||
map { exists( $borrower{$_} ) ? ( $_ => $borrower{$_} ) : () } @columns
|
||||
}
|
||||
)->store;
|
||||
$patron->discard_changes;
|
||||
die "Insert of new patron failed" unless $patron;
|
||||
$borrowernumber = $patron->borrowernumber;
|
||||
C4::Members::Messaging::SetMessagingPreferencesFromDefaults(
|
||||
|
|
|
|||
|
|
@ -135,6 +135,8 @@ sub _autocreate {
|
|||
}
|
||||
|
||||
my $patron = Koha::Patron->new( \%borrower )->store;
|
||||
$patron->discard_changes;
|
||||
|
||||
C4::Members::Messaging::SetMessagingPreferencesFromDefaults(
|
||||
{
|
||||
borrowernumber => $patron->borrowernumber,
|
||||
|
|
|
|||
|
|
@ -323,17 +323,17 @@ sub SearchAuthorities {
|
|||
if ( C4::Context->preference('ShowHeadingUse') ) {
|
||||
# checking valid heading use
|
||||
my $f008 = $authrecord->field('008');
|
||||
my $pos14to16 = substr( $f008->data, 14, 3 );
|
||||
my $main = substr( $pos14to16, 0, 1 );
|
||||
$newline{main} = 1 if $main eq 'a';
|
||||
my $subject = substr( $pos14to16, 1, 1);
|
||||
$newline{subject} = 1 if $subject eq 'a';
|
||||
my $series = substr( $pos14to16, 2, 1 );
|
||||
$newline{series} = 1 if $series eq 'a';
|
||||
if ($f008) {
|
||||
my $pos14to16 = substr( $f008->data, 14, 3 );
|
||||
my $main = substr( $pos14to16, 0, 1 );
|
||||
$newline{main} = 1 if $main eq 'a';
|
||||
my $subject = substr( $pos14to16, 1, 1 );
|
||||
$newline{subject} = 1 if $subject eq 'a';
|
||||
my $series = substr( $pos14to16, 2, 1 );
|
||||
$newline{series} = 1 if $series eq 'a';
|
||||
}
|
||||
}
|
||||
|
||||
$newline{authtype} = defined($thisauthtype) ?
|
||||
$thisauthtype->authtypetext : '';
|
||||
$newline{authtype} = defined($thisauthtype) ? $thisauthtype->authtypetext : '';
|
||||
$newline{summary} = $summary;
|
||||
$newline{even} = $counter % 2;
|
||||
$newline{reported_tag} = $reported_tag;
|
||||
|
|
|
|||
|
|
@ -94,11 +94,12 @@ sub max {
|
|||
return $self->db_max;
|
||||
}
|
||||
sub db_max {
|
||||
my $self = shift;
|
||||
my $query = "SELECT max(abs(barcode)) FROM items LIMIT 1"; # Possible problem if multiple barcode types populated
|
||||
my $sth = C4::Context->dbh->prepare($query);
|
||||
$sth->execute();
|
||||
return $sth->fetchrow_array || $self->initial;
|
||||
my $self = shift;
|
||||
my $query = "SELECT max(abs(CAST(barcode AS UNSIGNED))) FROM items LIMIT 1"
|
||||
; # Possible problem if multiple barcode types populated
|
||||
my $sth = C4::Context->dbh->prepare($query);
|
||||
$sth->execute();
|
||||
return $sth->fetchrow_array || $self->initial;
|
||||
}
|
||||
sub next_value {
|
||||
my $self = shift;
|
||||
|
|
|
|||
|
|
@ -555,9 +555,13 @@ sub DelBiblio {
|
|||
|
||||
# We delete any existing holds
|
||||
my $holds = $biblio->holds;
|
||||
$holds->update( { deleted_biblionumber => $biblionumber }, { no_triggers => 1 } );
|
||||
my $old_holds = $biblio->old_holds;
|
||||
$old_holds->update( { deleted_biblionumber => $biblionumber }, { no_triggers => 1 } );
|
||||
while ( my $hold = $holds->next ) {
|
||||
|
||||
# no need to update the holds queue on each step, we'll do it at the end
|
||||
$hold->cancel({ skip_holds_queue => 1 });
|
||||
$hold->cancel( { skip_holds_queue => 1 } );
|
||||
}
|
||||
|
||||
# We update any existing orders
|
||||
|
|
|
|||
|
|
@ -1266,9 +1266,8 @@ sub CanBookBeIssued {
|
|||
|
||||
## CHECK AGE RESTRICTION
|
||||
my $agerestriction = $biblioitem->agerestriction;
|
||||
my ( $restriction_age, $daysToAgeRestriction ) =
|
||||
GetAgeRestriction( $agerestriction, $patron->unblessed );
|
||||
if ( $daysToAgeRestriction && $daysToAgeRestriction > 0 ) {
|
||||
my $restriction_age = GetAgeRestriction( $agerestriction );
|
||||
if ( $restriction_age && $patron->dateofbirth && $restriction_age > $patron->get_age() ) {
|
||||
if ( C4::Context->preference('AgeRestrictionOverride') ) {
|
||||
$needsconfirmation{AGE_RESTRICTION} = "$agerestriction";
|
||||
}
|
||||
|
|
@ -2461,7 +2460,7 @@ sub AddReturn {
|
|||
ccode => $item->ccode,
|
||||
categorycode => $categorycode,
|
||||
interface => C4::Context->interface,
|
||||
}) unless ( $skip_localuse && $stat_type eq 'localuse' );
|
||||
}) unless ( $skip_localuse && !$issue );
|
||||
|
||||
# Send a check-in slip. # NOTE: borrower may be undef. Do not try to send messages then.
|
||||
if ( $patron ) {
|
||||
|
|
@ -4421,21 +4420,15 @@ sub IsItemIssued {
|
|||
|
||||
=head2 GetAgeRestriction
|
||||
|
||||
my ($ageRestriction, $daysToAgeRestriction) = GetAgeRestriction($record_restrictions, $borrower);
|
||||
my ($ageRestriction, $daysToAgeRestriction) = GetAgeRestriction($record_restrictions);
|
||||
|
||||
if($daysToAgeRestriction <= 0) { #Borrower is allowed to access this material, as they are older or as old as the agerestriction }
|
||||
if($daysToAgeRestriction > 0) { #Borrower is this many days from meeting the agerestriction }
|
||||
my $ageRestriction = GetAgeRestriction($record_restrictions);
|
||||
|
||||
@PARAM1 the koha.biblioitems.agerestriction value, like K18, PEGI 13, ...
|
||||
@PARAM2 a borrower-object with koha.borrowers.dateofbirth. (OPTIONAL)
|
||||
@RETURNS The age restriction age in years and the days to fulfill the age restriction for the given borrower.
|
||||
Negative days mean the borrower has gone past the age restriction age.
|
||||
@RETURNS The age restriction age in years.
|
||||
|
||||
=cut
|
||||
|
||||
sub GetAgeRestriction {
|
||||
my ($record_restrictions, $borrower) = @_;
|
||||
my ($record_restrictions) = @_;
|
||||
my $markers = C4::Context->preference('AgeRestrictionMarker');
|
||||
|
||||
return unless $record_restrictions;
|
||||
|
|
@ -4470,26 +4463,7 @@ sub GetAgeRestriction {
|
|||
last if ( $restriction_year > 0 );
|
||||
}
|
||||
|
||||
#Check if the borrower is age restricted for this material and for how long.
|
||||
if ($restriction_year && $borrower) {
|
||||
if ( $borrower->{'dateofbirth'} ) {
|
||||
my @alloweddate = split /-/, $borrower->{'dateofbirth'};
|
||||
$alloweddate[0] += $restriction_year;
|
||||
|
||||
#Prevent runime eror on leap year (invalid date)
|
||||
if ( ( $alloweddate[1] == 2 ) && ( $alloweddate[2] == 29 ) ) {
|
||||
$alloweddate[2] = 28;
|
||||
}
|
||||
|
||||
#Get how many days the borrower has to reach the age restriction
|
||||
my @Today = split /-/, dt_from_string()->ymd();
|
||||
my $daysToAgeRestriction = Date_to_Days(@alloweddate) - Date_to_Days(@Today);
|
||||
#Negative days means the borrower went past the age restriction age
|
||||
return ($restriction_year, $daysToAgeRestriction);
|
||||
}
|
||||
}
|
||||
|
||||
return ($restriction_year);
|
||||
return $restriction_year;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ sub GetRecords {
|
|||
|
||||
my $biblioitem = $biblio->biblioitem->unblessed;
|
||||
|
||||
my $record = $biblio->metadata->record({ embed_items => 1 });
|
||||
my $record = $biblio->metadata->record({ embed_items => 1, opac => 1, });
|
||||
if ($record) {
|
||||
$biblioitem->{marcxml} = $record->as_xml_record( C4::Context->preference('marcflavour') );
|
||||
}
|
||||
|
|
@ -236,7 +236,7 @@ sub GetRecords {
|
|||
foreach my $checkout (@$checkouts) {
|
||||
delete $checkout->{'borrowernumber'};
|
||||
}
|
||||
my @items = $biblio->items->as_list;
|
||||
my @items = $biblio->items->filter_by_visible_in_opac->as_list;
|
||||
|
||||
$biblioitem->{items}->{item} = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -291,6 +291,7 @@ sub _export_table_csv
|
|||
for my $field (@fields) {
|
||||
my $value = $hashRef->{$field} // q||;
|
||||
$value =~ s/[\r\n]//g;
|
||||
$value =~ s/"/""/g;
|
||||
$$strCSV .= '"' . $value . '",';
|
||||
}
|
||||
chop $$strCSV;
|
||||
|
|
|
|||
15
C4/Items.pm
15
C4/Items.pm
|
|
@ -45,6 +45,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
use Carp qw( croak );
|
||||
use C4::Circulation qw( barcodedecode );
|
||||
use C4::Context;
|
||||
use C4::Koha;
|
||||
use C4::Biblio qw( GetMarcStructure TransformMarcToKoha );
|
||||
|
|
@ -459,11 +460,15 @@ sub CheckItemPreSave {
|
|||
my %errors = ();
|
||||
|
||||
# check for duplicate barcode
|
||||
if (exists $item_ref->{'barcode'} and defined $item_ref->{'barcode'}) {
|
||||
my $existing_item= Koha::Items->find({barcode => $item_ref->{'barcode'}});
|
||||
if ( exists $item_ref->{'barcode'} and defined $item_ref->{'barcode'} ) {
|
||||
my $barcode = C4::Circulation::barcodedecode( $item_ref->{'barcode'} );
|
||||
my $existing_item = Koha::Items->find( { barcode => $barcode } );
|
||||
if ($existing_item) {
|
||||
if (!exists $item_ref->{'itemnumber'} # new item
|
||||
or $item_ref->{'itemnumber'} != $existing_item->itemnumber) { # existing item
|
||||
if (
|
||||
!exists $item_ref->{'itemnumber'} # new item
|
||||
or $item_ref->{'itemnumber'} != $existing_item->itemnumber
|
||||
)
|
||||
{ # existing item
|
||||
$errors{'duplicate_barcode'} = $item_ref->{'barcode'};
|
||||
}
|
||||
}
|
||||
|
|
@ -1178,7 +1183,7 @@ sub SearchItems {
|
|||
LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
|
||||
LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
|
||||
LEFT JOIN biblio_metadata ON biblio_metadata.biblionumber = biblio.biblionumber
|
||||
LEFT JOIN issues ON issues.itemnumber = items.itemnumber
|
||||
LEFT JOIN issues USING (itemnumber)
|
||||
WHERE 1
|
||||
};
|
||||
if (defined $where_str and $where_str ne '') {
|
||||
|
|
|
|||
|
|
@ -1569,8 +1569,8 @@ sub _wrap_html {
|
|||
$css = qq{<link rel="stylesheet" type="text/css" href="$css">} if $css;
|
||||
return <<EOS;
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang="en" xml:lang="en" xmlns="https://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>$title</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
|
|
|||
|
|
@ -288,10 +288,12 @@ sub CalcFine {
|
|||
&& $amount > $issuing_rule->{overduefinescap};
|
||||
|
||||
# This must be moved to Koha::Item (see also similar code in C4::Accounts::chargelostitem
|
||||
$item->{replacementprice} ||= $itemtype->defaultreplacecost
|
||||
if $itemtype
|
||||
&& ( ! defined $item->{replacementprice} || $item->{replacementprice} == 0 )
|
||||
&& C4::Context->preference("useDefaultReplacementCost");
|
||||
if ( $itemtype
|
||||
&& ( !defined $item->{replacementprice} || $item->{replacementprice} + .0 == 0 )
|
||||
&& C4::Context->preference("useDefaultReplacementCost") )
|
||||
{
|
||||
$item->{replacementprice} = $itemtype->defaultreplacecost;
|
||||
}
|
||||
|
||||
$amount = $item->{replacementprice} if ( $issuing_rule->{cap_fine_to_replacement_price} && $item->{replacementprice} && $amount > $item->{replacementprice} );
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ use Koha::Holds;
|
|||
use Koha::ItemTypes;
|
||||
use Koha::Items;
|
||||
use Koha::Libraries;
|
||||
use Koha::Old::Holds;
|
||||
use Koha::Patrons;
|
||||
use Koha::Plugins;
|
||||
use Koha::Policy::Holds;
|
||||
|
|
@ -485,10 +484,6 @@ sub CanItemBeReserved {
|
|||
}
|
||||
}
|
||||
|
||||
# we retrieve borrowers and items informations #
|
||||
# item->{itype} will come for biblioitems if necessery
|
||||
my $borrower = $patron->unblessed;
|
||||
|
||||
# If an item is damaged and we don't allow holds on damaged items, we can stop right here
|
||||
return _cache { status =>'damaged' }
|
||||
if ( $item->damaged
|
||||
|
|
@ -497,9 +492,8 @@ sub CanItemBeReserved {
|
|||
if( GetMarcFromKohaField('biblioitems.agerestriction') ){
|
||||
my $biblio = $item->biblio;
|
||||
# Check for the age restriction
|
||||
my ( $ageRestriction, $daysToAgeRestriction ) =
|
||||
C4::Circulation::GetAgeRestriction( $biblio->biblioitem->agerestriction, $borrower );
|
||||
return _cache { status => 'ageRestricted' } if $daysToAgeRestriction && $daysToAgeRestriction > 0;
|
||||
my $ageRestriction = C4::Circulation::GetAgeRestriction( $biblio->biblioitem->agerestriction );
|
||||
return _cache { status => 'ageRestricted' } if $ageRestriction && $patron->dateofbirth && $ageRestriction > $patron->get_age();
|
||||
}
|
||||
|
||||
# Check that the patron doesn't have an item level hold on this item already
|
||||
|
|
@ -527,14 +521,14 @@ sub CanItemBeReserved {
|
|||
}
|
||||
elsif ( $controlbranch eq "PatronLibrary" ) {
|
||||
$branchfield = "borrowers.branchcode";
|
||||
$reserves_control_branch = $borrower->{branchcode};
|
||||
$reserves_control_branch = $patron->branchcode;
|
||||
}
|
||||
|
||||
# we retrieve rights
|
||||
if (
|
||||
my $reservesallowed = Koha::CirculationRules->get_effective_rule({
|
||||
itemtype => $item->effective_itemtype,
|
||||
categorycode => $borrower->{categorycode},
|
||||
categorycode => $patron->categorycode,
|
||||
branchcode => $reserves_control_branch,
|
||||
rule_name => 'reservesallowed',
|
||||
})
|
||||
|
|
@ -547,7 +541,7 @@ sub CanItemBeReserved {
|
|||
}
|
||||
|
||||
my $rights = Koha::CirculationRules->get_effective_rules({
|
||||
categorycode => $borrower->{'categorycode'},
|
||||
categorycode => $patron->categorycode,
|
||||
itemtype => $item->effective_itemtype,
|
||||
branchcode => $reserves_control_branch,
|
||||
rules => ['holds_per_record','holds_per_day']
|
||||
|
|
@ -656,7 +650,7 @@ sub CanItemBeReserved {
|
|||
}
|
||||
|
||||
if ( $branchitemrule->{holdallowed} eq 'from_home_library'
|
||||
&& $borrower->{branchcode} ne $item->homebranch )
|
||||
&& $patron->branchcode ne $item->homebranch )
|
||||
{
|
||||
return _cache { status => 'cannotReserveFromOtherBranches' };
|
||||
}
|
||||
|
|
@ -685,7 +679,7 @@ sub CanItemBeReserved {
|
|||
if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) {
|
||||
return _cache { status => 'pickupNotInHoldGroup' };
|
||||
}
|
||||
if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
|
||||
if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $patron->branchcode})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
|
||||
return _cache { status => 'pickupNotInHoldGroup' };
|
||||
}
|
||||
}
|
||||
|
|
@ -1602,6 +1596,7 @@ sub _FixPriority {
|
|||
$hold = Koha::Holds->find( $reserve_id );
|
||||
if (!defined $hold){
|
||||
# may have already been checked out and hold fulfilled
|
||||
require Koha::Old::Holds;
|
||||
$hold = Koha::Old::Holds->find( $reserve_id );
|
||||
}
|
||||
return unless $hold;
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ sub end_patron_session {
|
|||
my ($self, $patron_id) = @_;
|
||||
|
||||
# success?, screen_msg, print_line
|
||||
return (1, 'Thank you !', '');
|
||||
return (1, 'Thank you!', '');
|
||||
}
|
||||
|
||||
sub pay_fee {
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ sub new {
|
|||
}
|
||||
}
|
||||
|
||||
# Get currency 3 chars max
|
||||
my $currency = substr Koha::Acquisition::Currencies->get_active->currency, 0, 3;
|
||||
|
||||
my $circ_blocked =( C4::Context->preference('OverduesBlockCirc') ne "noblock" && defined $flags->{ODUES}->{itemlist} ) ? 1 : 0;
|
||||
{
|
||||
no warnings; # any of these $kp->{fields} being concat'd could be undef
|
||||
|
|
@ -164,6 +167,7 @@ sub new {
|
|||
fine_blocked => $fine_blocked,
|
||||
fee_limit => $fee_limit,
|
||||
userid => $kp->{userid},
|
||||
currency => $currency,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +209,7 @@ sub new {
|
|||
}
|
||||
}
|
||||
|
||||
# FIXME: populate fine_items recall_items
|
||||
# FIXME: populate recall_items
|
||||
$ilspatron{unavail_holds} = _get_outstanding_holds($kp->{borrowernumber});
|
||||
|
||||
my $pending_checkouts = $patron->pending_checkouts;
|
||||
|
|
@ -390,6 +394,7 @@ sub x_items {
|
|||
|
||||
my $item_list = [];
|
||||
if ($self->{$array_var}) {
|
||||
|
||||
if ($start && $start > 1) {
|
||||
--$start;
|
||||
}
|
||||
|
|
@ -397,6 +402,7 @@ sub x_items {
|
|||
$start = 0;
|
||||
}
|
||||
if ( $end && $end < @{$self->{$array_var}} ) {
|
||||
--$end;
|
||||
}
|
||||
else {
|
||||
$end = @{$self->{$array_var}};
|
||||
|
|
@ -430,29 +436,33 @@ sub charged_items {
|
|||
return $self->x_items('items', @_);
|
||||
}
|
||||
sub fine_items {
|
||||
|
||||
require Koha::Database;
|
||||
require Template;
|
||||
|
||||
my $self = shift;
|
||||
my $start = shift;
|
||||
my $end = shift;
|
||||
my $self = shift;
|
||||
my $start = shift;
|
||||
my $end = shift;
|
||||
my $server = shift;
|
||||
|
||||
my @fees = Koha::Database->new()->schema()->resultset('Accountline')->search(
|
||||
my @fees =
|
||||
Koha::Database->new()->schema()->resultset('Accountline')->search(
|
||||
{
|
||||
borrowernumber => $self->{borrowernumber},
|
||||
amountoutstanding => { '>' => '0' },
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
$start = $start ? $start - 1 : 0;
|
||||
$end = $end ? $end - 1 : scalar @fees - 1;
|
||||
|
||||
my $av_field_template = $server ? $server->{account}->{av_field_template} : undef;
|
||||
$av_field_template ||= "[% accountline.description %] [% accountline.amountoutstanding | format('%.2f') %]";
|
||||
my $av_field_template =
|
||||
$server ? $server->{account}->{av_field_template} : undef;
|
||||
$av_field_template ||=
|
||||
"[% accountline.description %] [% accountline.amountoutstanding | format('%.2f') %]";
|
||||
|
||||
my @return_values;
|
||||
for ( my $i = $start; $i <= $end; $i++ ) {
|
||||
for ( my $i = $start ; $i <= $end ; $i++ ) {
|
||||
my $fee = $fees[$i];
|
||||
|
||||
next unless $fee;
|
||||
|
|
@ -462,7 +472,9 @@ sub fine_items {
|
|||
}
|
||||
|
||||
return \@return_values;
|
||||
|
||||
}
|
||||
|
||||
sub recall_items {
|
||||
my $self = shift;
|
||||
return $self->x_items('recall_items', @_);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use FindBin qw($Bin);
|
|||
use lib "$Bin";
|
||||
use Net::Server::PreFork;
|
||||
use IO::Socket::INET;
|
||||
use Socket qw(:DEFAULT :crlf);
|
||||
use Socket qw(:DEFAULT :crlf TCP_KEEPIDLE TCP_KEEPINTVL IPPROTO_TCP);
|
||||
use Scalar::Util qw(blessed);
|
||||
require UNIVERSAL::require;
|
||||
|
||||
|
|
@ -90,6 +90,126 @@ push @parms, 'group=' . $>;
|
|||
# This is the main event.
|
||||
__PACKAGE__ ->run(@parms);
|
||||
|
||||
#
|
||||
# Server
|
||||
#
|
||||
|
||||
=head3 options
|
||||
|
||||
As per Net::Server documentation, override "options" to provide your own
|
||||
custom options to the Net::Server* object. This allows us to use the Net::Server
|
||||
infrastructure for configuration rather than hacking our own configuration into the
|
||||
object.
|
||||
|
||||
=cut
|
||||
|
||||
sub options {
|
||||
my $self = shift;
|
||||
my $prop = $self->{'server'};
|
||||
my $template = shift;
|
||||
|
||||
# setup options in the parent classes
|
||||
$self->SUPER::options($template);
|
||||
|
||||
$prop->{'custom_tcp_keepalive'} ||= undef;
|
||||
$template->{'custom_tcp_keepalive'} = \$prop->{'custom_tcp_keepalive'};
|
||||
|
||||
$prop->{'custom_tcp_keepalive_time'} ||= undef;
|
||||
$template->{'custom_tcp_keepalive_time'} = \$prop->{'custom_tcp_keepalive_time'};
|
||||
|
||||
$prop->{'custom_tcp_keepalive_intvl'} ||= undef;
|
||||
$template->{'custom_tcp_keepalive_intvl'} = \$prop->{'custom_tcp_keepalive_intvl'};
|
||||
}
|
||||
|
||||
=head3 post_configure_hook
|
||||
|
||||
As per Net::Server documentation, this method validates our custom configuration.
|
||||
|
||||
=cut
|
||||
|
||||
sub post_configure_hook {
|
||||
my $self = shift;
|
||||
my $prop = $self->{'server'};
|
||||
if ( defined $prop->{'custom_tcp_keepalive'} && $prop->{'custom_tcp_keepalive'} ) {
|
||||
|
||||
#NOTE: Any true value defined is forced to 1 just for the sake of predictability
|
||||
$prop->{'custom_tcp_keepalive'} = 1;
|
||||
}
|
||||
|
||||
foreach my $key ( 'custom_tcp_keepalive_time', 'custom_tcp_keepalive_intvl' ) {
|
||||
my $value = $prop->{$key};
|
||||
|
||||
#NOTE: A regex is used here to detect a positive integer, as int() returns integers but does not validate them
|
||||
#NOTE: We do not allow zero as it can lead to problematic behaviour
|
||||
if ( $value && $value =~ /^\d+$/ ) {
|
||||
|
||||
#NOTE: Strictly, you must convert into an integer as a string will cause setsockopt to fail
|
||||
$prop->{$key} = int($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
=head3 post_accept_hook
|
||||
|
||||
This hook occurs after the client connection socket is created, which gives
|
||||
us an opportunity to enable support for TCP keepalives using the SO_KEEPALIVE
|
||||
socket option.
|
||||
|
||||
By default, the kernel-level defaults (in seconds) are used. You can view these in the output of "sysctl -a":
|
||||
net.ipv4.tcp_keepalive_intvl = 75
|
||||
net.ipv4.tcp_keepalive_time = 7200
|
||||
|
||||
Alternatively, you can use "custom_tcp_keepalive_time" and "custom_tcp_keepalive_intvl" to define
|
||||
your own custom values for the socket. Note that these parameters are defined at the top server-level
|
||||
and not on the listener-level.
|
||||
|
||||
If you lower "custom_tcp_keepalive_time" below 75, you will also need to set "custom_tcp_keepalive_intvl".
|
||||
The "tcp_keepalive_time" is the initial time used for the keepalive timer, and the "tcp_keepalive_intvl"
|
||||
is the time used for subsequent keepalive timers. However, timers only send keepalive ACKs if the idle time
|
||||
elapsed is greater than "tcp_keepalive_time".
|
||||
|
||||
Thus, if "tcp_keepalive_time = 10" and "tcp_keepalive_intvl = 5", a keepalive ACK will be sent every 10 seconds
|
||||
of idle time. If "tcp_keepalive_intvl = 10" and "tcp_keepalive_time = 5", a keepalive ACK will be sent after 5
|
||||
seconds of idle time, and the next keepalive ACK will be sent after 10 seconds of idle time. Generally speaking,
|
||||
it's best to set "tcp_keepalive_time" to be higher than "tcp_keepalive_intvl".
|
||||
|
||||
Reminder: once these settings are set on the socket, they are handled by the operating system kernel, and not
|
||||
by the SIP server application. If you are having trouble with your settings, monitor your TCP traffic using
|
||||
a tool such as "tcpdump" to review and refine how they work.
|
||||
|
||||
=cut
|
||||
|
||||
sub post_accept_hook {
|
||||
my $self = shift;
|
||||
my $prop = $self->{'server'};
|
||||
my $client = shift || $prop->{'client'};
|
||||
|
||||
my $tcp_keepalive = $prop->{custom_tcp_keepalive};
|
||||
my $tcp_keepalive_time = $prop->{custom_tcp_keepalive_time};
|
||||
my $tcp_keepalive_intvl = $prop->{custom_tcp_keepalive_intvl};
|
||||
|
||||
if ($tcp_keepalive) {
|
||||
|
||||
#NOTE: set the SO_KEEPALIVE option to enable TCP keepalives
|
||||
setsockopt( $client, SOL_SOCKET, SO_KEEPALIVE, 1 )
|
||||
or die "Unable to set SO_KEEPALIVE: $!";
|
||||
|
||||
if ($tcp_keepalive_time) {
|
||||
|
||||
#NOTE: override "net.ipv4.tcp_keepalive_time" kernel parameter for this socket
|
||||
setsockopt( $client, IPPROTO_TCP, TCP_KEEPIDLE, $tcp_keepalive_time )
|
||||
or die "Unable to set TCP_KEEPIDLE: $!";
|
||||
}
|
||||
|
||||
if ($tcp_keepalive_intvl) {
|
||||
|
||||
#NOTE: override "net.ipv4.tcp_keepalive_intvl" kernel parameter for this socket
|
||||
setsockopt( $client, IPPROTO_TCP, TCP_KEEPINTVL, $tcp_keepalive_intvl )
|
||||
or die "Unable to set TCP_KEEPINTVL: $!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Child
|
||||
#
|
||||
|
|
|
|||
|
|
@ -187,34 +187,33 @@ sub boolspace {
|
|||
#
|
||||
|
||||
sub write_msg {
|
||||
my ($self, $msg, $file, $terminator, $encoding) = @_;
|
||||
my ( $self, $msg, $server ) = @_;
|
||||
my $terminator = $server->{account}->{terminator};
|
||||
my $encoding = $server->{account}->{encoding};
|
||||
|
||||
$terminator ||= q{};
|
||||
$terminator = ( $terminator eq 'CR' ) ? $CR : $CRLF;
|
||||
|
||||
$msg = encode($encoding, $msg) if ( $encoding );
|
||||
my $separator = $server->{account}->{convert_nonprinting_characters};
|
||||
$msg =~ s/[^[:print:]]/$separator/g if defined $separator;
|
||||
|
||||
$msg = encode( $encoding, $msg ) if ($encoding);
|
||||
|
||||
my $cksum;
|
||||
|
||||
# $msg = encode_utf8($msg);
|
||||
if ($error_detection) {
|
||||
if (defined($self->{seqno})) {
|
||||
if ( defined( $self->{seqno} ) ) {
|
||||
$msg .= 'AY' . $self->{seqno};
|
||||
}
|
||||
$msg .= 'AZ';
|
||||
$cksum = checksum($msg);
|
||||
$msg .= sprintf('%04.4X', $cksum);
|
||||
$msg .= sprintf( '%04.4X', $cksum );
|
||||
}
|
||||
|
||||
|
||||
if ($file) {
|
||||
$file->autoflush(1);
|
||||
print $file $msg, $terminator;
|
||||
} else {
|
||||
STDOUT->autoflush(1);
|
||||
print $msg, $terminator;
|
||||
siplog("LOG_INFO", "OUTPUT MSG: '$msg'");
|
||||
}
|
||||
STDOUT->autoflush(1);
|
||||
print $msg, $terminator;
|
||||
siplog( "LOG_INFO", "OUTPUT MSG: '$msg'" );
|
||||
|
||||
$last_response = $msg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -504,12 +504,12 @@ sub handle_patron_status {
|
|||
|
||||
$ils->check_inst_id( $fields->{ (FID_INST_ID) }, "handle_patron_status" );
|
||||
$patron = $ils->find_patron( $fields->{ (FID_PATRON_ID) } );
|
||||
if ( C4::Context->preference('TrackLastPatronActivityTriggers') ) {
|
||||
if ( C4::Context->preference('TrackLastPatronActivityTriggers') && $patron ) {
|
||||
my $koha_patron = Koha::Patrons->find($patron->{borrowernumber});
|
||||
$koha_patron->update_lastseen('connection');
|
||||
}
|
||||
$resp = build_patron_status( $patron, $lang, $fields, $server );
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
return (PATRON_STATUS_REQ);
|
||||
}
|
||||
|
||||
|
|
@ -649,7 +649,7 @@ sub handle_checkout {
|
|||
}
|
||||
}
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
return (CHECKOUT);
|
||||
}
|
||||
|
||||
|
|
@ -748,7 +748,7 @@ sub handle_checkin {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server );
|
||||
$resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (CHECKIN);
|
||||
}
|
||||
|
|
@ -795,7 +795,7 @@ sub handle_block_patron {
|
|||
}
|
||||
|
||||
$resp = build_patron_status( $patron, $patron->language, $fields, $server );
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
return (BLOCK_PATRON);
|
||||
}
|
||||
|
||||
|
|
@ -836,7 +836,7 @@ sub handle_request_acs_resend {
|
|||
|
||||
# We haven't sent anything yet, so respond with a
|
||||
# REQUEST_SC_RESEND msg (p. 16)
|
||||
$self->write_msg( REQUEST_SC_RESEND, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( REQUEST_SC_RESEND, $server );
|
||||
} elsif ( ( length($last_response) < 9 )
|
||||
|| substr( $last_response, -9, 2 ) ne 'AY' ) {
|
||||
|
||||
|
|
@ -850,7 +850,7 @@ sub handle_request_acs_resend {
|
|||
# Cut out the sequence number and checksum, since the old
|
||||
# checksum is wrong for the resent message.
|
||||
my $rebuilt = substr( $last_response, 0, -9 );
|
||||
$self->write_msg( $rebuilt, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $rebuilt, $server );
|
||||
}
|
||||
|
||||
return REQUEST_ACS_RESEND;
|
||||
|
|
@ -932,7 +932,7 @@ sub handle_login {
|
|||
$status = login_core( $server, $uid, $pwd );
|
||||
}
|
||||
|
||||
$self->write_msg( LOGIN_RESP . $status, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( LOGIN_RESP . $status, $server );
|
||||
return $status ? LOGIN : '';
|
||||
}
|
||||
|
||||
|
|
@ -971,7 +971,7 @@ sub summary_info {
|
|||
my $fid = $summary_map[$summary_type]->{fid};
|
||||
my $itemlist = &$func( $patron, $start, $end, $server );
|
||||
|
||||
siplog( "LOG_DEBUG", "summary_info: list = (%s)", join( ", ", map{ $_->{barcode} } @{$itemlist} ) );
|
||||
siplog( "LOG_DEBUG", "summary_info: list = (%s)", join( ", ", map { $_->{barcode} } @{$itemlist} ) );
|
||||
foreach my $i ( @{$itemlist} ) {
|
||||
$resp .= add_field( $fid, $i->{barcode}, $server );
|
||||
}
|
||||
|
|
@ -1101,7 +1101,7 @@ sub handle_patron_info {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, INVALID_CARD, $server );
|
||||
}
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
return (PATRON_INFO);
|
||||
}
|
||||
|
||||
|
|
@ -1128,7 +1128,7 @@ sub handle_end_patron_session {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, $screen_msg, $server );
|
||||
$resp .= maybe_add( FID_PRINT_LINE, $print_line, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (END_PATRON_SESSION);
|
||||
}
|
||||
|
|
@ -1210,7 +1210,7 @@ sub handle_fee_paid {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server );
|
||||
$resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (FEE_PAID);
|
||||
}
|
||||
|
|
@ -1303,7 +1303,7 @@ sub handle_item_information {
|
|||
$resp .= $item->build_custom_field_string( $server );
|
||||
}
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (ITEM_INFORMATION);
|
||||
}
|
||||
|
|
@ -1353,7 +1353,7 @@ sub handle_item_status_update {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server );
|
||||
$resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (ITEM_STATUS_UPDATE);
|
||||
}
|
||||
|
|
@ -1407,7 +1407,7 @@ sub handle_patron_enable {
|
|||
|
||||
$resp .= add_field( FID_INST_ID, $ils->institution, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (PATRON_ENABLE);
|
||||
}
|
||||
|
|
@ -1472,7 +1472,7 @@ sub handle_hold {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server );
|
||||
$resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (HOLD);
|
||||
}
|
||||
|
|
@ -1559,7 +1559,7 @@ sub handle_renew {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server );
|
||||
$resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (RENEW);
|
||||
}
|
||||
|
|
@ -1612,7 +1612,7 @@ sub handle_renew_all {
|
|||
$resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server );
|
||||
$resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server );
|
||||
|
||||
$self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $resp, $server );
|
||||
|
||||
return (RENEW_ALL);
|
||||
}
|
||||
|
|
@ -1718,7 +1718,7 @@ sub send_acs_status {
|
|||
|
||||
# Do we want to tell the terminal its location?
|
||||
|
||||
$self->write_msg( $msg, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
|
||||
$self->write_msg( $msg, $server );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,26 @@ sub text{
|
|||
my $line = shift;
|
||||
my $work = shift; # original text
|
||||
my $is_cdata = shift;
|
||||
# If there is a split template toolkit tag
|
||||
if ( $work =~ m/^(?:(?!\[%).)*?%\]/s ) {
|
||||
my @strings = ($&);
|
||||
my $token;
|
||||
$work = $';
|
||||
while ( $token = pop @tokens ) {
|
||||
if ( $token->string =~ m/\[%.*?$/s ) {
|
||||
push @tokens, C4::TmplToken->new( $`, $token->type, $token->line_number, $token->pathname );
|
||||
push @strings, $&;
|
||||
last;
|
||||
} else {
|
||||
push @strings, $token->string;
|
||||
}
|
||||
}
|
||||
push @tokens,
|
||||
C4::TmplToken->new(
|
||||
join( '', reverse @strings ), C4::TmplTokenType::DIRECTIVE,
|
||||
$token ? $token->line_number : $line, $self->{filename}
|
||||
);
|
||||
}
|
||||
while($work){
|
||||
# if there is a template_toolkit tag
|
||||
if( $work =~ m/\[%.*?%\]/ ){
|
||||
|
|
|
|||
|
|
@ -320,9 +320,9 @@ sub buildKohaItemsNamespace {
|
|||
$status = 'other';
|
||||
$substatus = 'In transit';
|
||||
}
|
||||
elsif ($item->damaged) {
|
||||
$status = 'other';
|
||||
$substatus = "Damaged";
|
||||
elsif ( $item->damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') ) {
|
||||
$status = 'other';
|
||||
$substatus = 'Damaged';
|
||||
}
|
||||
elsif ($item->itemlost) {
|
||||
$status = 'other';
|
||||
|
|
|
|||
2
Koha.pm
2
Koha.pm
|
|
@ -29,7 +29,7 @@ use vars qw{ $VERSION };
|
|||
# - #4 : the developer version. The 4th number is the database subversion.
|
||||
# used by developers when the database changes. updatedatabase take care of the changes itself
|
||||
# and is automatically called by Auth.pm when needed.
|
||||
$VERSION = "24.05.05.000";
|
||||
$VERSION = "24.05.05.009";
|
||||
|
||||
sub version {
|
||||
return $VERSION;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ use Koha::Account::Offsets;
|
|||
use Koha::Database;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
use Koha::Exceptions::Account;
|
||||
use Koha::Items;
|
||||
use Koha::Patron::Debarments;
|
||||
|
||||
use base qw(Koha::Object Koha::Object::Mixin::AdditionalFields);
|
||||
|
|
@ -80,6 +79,7 @@ sub item {
|
|||
my ( $self ) = @_;
|
||||
my $rs = $self->_result->itemnumber;
|
||||
return unless $rs;
|
||||
require Koha::Item;
|
||||
return Koha::Item->_new_from_dbic( $rs );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,12 +81,13 @@ sub search_for_display {
|
|||
qq|(SELECT COUNT(*) FROM additional_contents_localizations WHERE lang='$lang' AND additional_content_id=me.additional_content_id)=0|;
|
||||
|
||||
my $search_params;
|
||||
$search_params->{location} = $params->{location};
|
||||
$search_params->{branchcode} = $params->{library_id} ? [ $params->{library_id}, undef ] : undef;
|
||||
$search_params->{published_on} = { '<=' => \'CAST(NOW() AS DATE)' };
|
||||
$search_params->{expirationdate} = [ '-or', { '>=' => \'CAST(NOW() AS DATE)' }, undef ];
|
||||
$search_params->{'additional_content.id'} = $params->{id} if $params->{id};
|
||||
$search_params->{location} = $params->{location};
|
||||
$search_params->{branchcode} = $params->{library_id} ? [ $params->{library_id}, undef ] : undef;
|
||||
$search_params->{published_on} = { '<=' => \'CAST(NOW() AS DATE)' } unless $params->{id};
|
||||
$search_params->{expirationdate} = [ '-or', { '>=' => \'CAST(NOW() AS DATE)' }, undef ] unless $params->{id};
|
||||
$search_params->{category} = $params->{category} if $params->{category};
|
||||
$search_params->{lang} = 'default' if !$lang || $lang eq 'default';
|
||||
$search_params->{lang} = 'default' if !$lang || $lang eq 'default';
|
||||
$search_params->{-or} = [ { 'lang' => $lang }, '-and' => [ 'lang', 'default', \$subquery ] ]
|
||||
if !$search_params->{lang};
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,26 @@ sub is_integer_only {
|
|||
return $self->_result->category->is_integer_only;
|
||||
}
|
||||
|
||||
=head3 to_api
|
||||
|
||||
my $json = $av->to_api;
|
||||
|
||||
Overloaded method that returns a JSON representation of the Koha::AuthorisedValue object,
|
||||
suitable for API output.
|
||||
|
||||
=cut
|
||||
|
||||
sub to_api {
|
||||
my ( $self, $params ) = @_;
|
||||
|
||||
my $response = $self->SUPER::to_api($params);
|
||||
my $overrides = {};
|
||||
|
||||
$overrides->{description} = $self->lib // q{};
|
||||
|
||||
return { %$response, %$overrides };
|
||||
}
|
||||
|
||||
=head2 Internal methods
|
||||
|
||||
=head3 _check_is_integer_only
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ sub read_file {
|
|||
my $delimiter = $file->{filename} =~ /\.tsv$/ ? "\t" : ",";
|
||||
my $quote_char = $file->{filename} =~ /\.tsv$/ ? "\"" : "\"";
|
||||
|
||||
open my $fh, "<", \$file_content or die;
|
||||
open my $fh, "<", \$file_content or die "Could not open file $file->{filename}: $!";
|
||||
my $csv = Text::CSV_XS->new(
|
||||
{
|
||||
sep_char => $delimiter,
|
||||
|
|
@ -241,14 +241,16 @@ sub read_file {
|
|||
my $headers_to_check = $csv->getline($fh);
|
||||
my $column_headers = rescue_EBSCO_files($headers_to_check);
|
||||
my $lines = $csv->getline_all( $fh, 0 );
|
||||
|
||||
my ( $cde, $str, $pos ) = $csv->error_diag();
|
||||
my $error = $cde ? "$cde, $str, $pos" : "";
|
||||
warn $error if $error;
|
||||
|
||||
close($fh);
|
||||
|
||||
return ( $column_headers, $lines, $error );
|
||||
unless($csv->eof()) {
|
||||
my ( $cde, $str, $pos ) = $csv->error_diag();
|
||||
my $error = $cde ? "$cde, $str, $pos" : "";
|
||||
warn $error if $error;
|
||||
return ( $column_headers, $lines, $error );
|
||||
}
|
||||
|
||||
return ( $column_headers, $lines );
|
||||
}
|
||||
|
||||
=head3 create_title_hash_from_line_data
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ sub process {
|
|||
$matcher_code = $matcher->code();
|
||||
$num_with_matches =
|
||||
BatchFindDuplicates( $batch_id, $matcher, 10, 50,
|
||||
sub { my $job_progress = shift; $self->progress( $self->progress + $job_progress )->store } );
|
||||
sub { my $job_progress = shift; $self->progress( $job_progress )->store } );
|
||||
SetImportBatchMatcher( $batch_id, $matcher_id );
|
||||
SetImportBatchOverlayAction( $batch_id, $overlay_action );
|
||||
SetImportBatchNoMatchAction( $batch_id, $nomatch_action );
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ use Koha::Item::Transfer::Limits;
|
|||
use Koha::Items;
|
||||
use Koha::Libraries;
|
||||
use Koha::Old::Checkouts;
|
||||
use Koha::Old::Holds;
|
||||
use Koha::Ratings;
|
||||
use Koha::Recalls;
|
||||
use Koha::RecordProcessor;
|
||||
|
|
@ -462,15 +463,14 @@ the I<OpacHiddenItems> system preference.
|
|||
sub hidden_in_opac {
|
||||
my ( $self, $params ) = @_;
|
||||
|
||||
return 0 unless C4::Context->preference('OpacHiddenItemsHidesRecord');
|
||||
|
||||
my $rules = $params->{rules} // {};
|
||||
|
||||
my @items = $self->items->as_list;
|
||||
|
||||
return 0 unless @items; # Do not hide if there is no item
|
||||
|
||||
# Ok, there are items, don't even try the rules unless OpacHiddenItemsHidesRecord
|
||||
return 0 unless C4::Context->preference('OpacHiddenItemsHidesRecord');
|
||||
|
||||
return !(any { !$_->hidden_in_opac({ rules => $rules }) } @items);
|
||||
}
|
||||
|
||||
|
|
@ -613,7 +613,8 @@ sub items {
|
|||
|
||||
my $items_rs = $self->_result->items;
|
||||
|
||||
return Koha::Items->_new_from_dbic( $items_rs ) unless $params->{host_items};
|
||||
return Koha::Items->_new_from_dbic($items_rs)
|
||||
unless $params->{host_items} && C4::Context->preference('EasyAnalyticalRecords');
|
||||
|
||||
my @itemnumbers = $items_rs->get_column('itemnumber')->all;
|
||||
my $host_itemnumbers = $self->_host_itemnumbers();
|
||||
|
|
@ -650,7 +651,7 @@ sub host_items {
|
|||
|
||||
my $host_itemnumbers = $self->_host_itemnumbers;
|
||||
|
||||
return Koha::Items->search( { itemnumber => { -in => $host_itemnumbers } } );
|
||||
return Koha::Items->search( { "me.itemnumber" => { -in => $host_itemnumbers } } );
|
||||
}
|
||||
|
||||
=head3 _host_itemnumbers
|
||||
|
|
@ -707,6 +708,21 @@ sub holds {
|
|||
return Koha::Holds->_new_from_dbic($hold_rs);
|
||||
}
|
||||
|
||||
=head3 old_holds
|
||||
|
||||
my $old_holds = $biblio->old_holds();
|
||||
|
||||
return the historic holds placed on this record
|
||||
|
||||
=cut
|
||||
|
||||
sub old_holds {
|
||||
my ( $self, $params, $attributes ) = @_;
|
||||
$attributes->{order_by} = 'priority' unless exists $attributes->{order_by};
|
||||
my $old_hold_rs = $self->_result->old_reserves->search( $params, $attributes );
|
||||
return Koha::Old::Holds->_new_from_dbic($old_hold_rs);
|
||||
}
|
||||
|
||||
=head3 current_holds
|
||||
|
||||
my $holds = $biblio->current_holds
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@ use Modern::Perl;
|
|||
|
||||
use Koha::Exceptions;
|
||||
|
||||
use Koha::Biblio::Metadata::Extractor::MARC::MARC21;
|
||||
use Koha::Biblio::Metadata::Extractor::MARC::UNIMARC;
|
||||
|
||||
=head1 API
|
||||
|
||||
=head2 Class methods
|
||||
|
|
@ -58,6 +55,8 @@ sub new {
|
|||
unless $valid_schemas->{$schema};
|
||||
|
||||
my $sub_class = "Koha::Biblio::Metadata::Extractor::MARC::$schema";
|
||||
require "Koha/Biblio/Metadata/Extractor/MARC/$schema.pm";
|
||||
|
||||
return $sub_class->new($params);
|
||||
}
|
||||
|
||||
|
|
|
|||
24
Koha/EDI.pm
24
Koha/EDI.pm
|
|
@ -45,6 +45,7 @@ use Koha::Plugins; # Adds plugin dirs to @INC
|
|||
use Koha::Plugins::Handler;
|
||||
use Koha::Acquisition::Baskets;
|
||||
use Koha::Acquisition::Booksellers;
|
||||
use Koha::Util::FrameworkPlugin qw( biblio_008 );
|
||||
|
||||
our $VERSION = 1.1;
|
||||
|
||||
|
|
@ -684,6 +685,10 @@ sub quote_item {
|
|||
if ( !defined $bib ) {
|
||||
$bib = {};
|
||||
my $bib_record = _create_bib_from_quote( $item, $quote );
|
||||
|
||||
# Check for and add default 008 as this is a mandatory field
|
||||
$bib_record = _handle_008_field($bib_record);
|
||||
|
||||
( $bib->{biblionumber}, $bib->{biblioitemnumber} ) =
|
||||
AddBiblio( $bib_record, q{} );
|
||||
$logger->trace("New biblio added $bib->{biblionumber}");
|
||||
|
|
@ -1215,6 +1220,17 @@ sub _create_item_from_quote {
|
|||
return $item_hash;
|
||||
}
|
||||
|
||||
sub _handle_008_field {
|
||||
my ($bib_record) = @_;
|
||||
|
||||
if ( !$bib_record->field('008') ) {
|
||||
my $default008 = biblio_008();
|
||||
$bib_record->insert_fields_ordered( MARC::Field->new( '008', $default008 ) );
|
||||
}
|
||||
|
||||
return $bib_record;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
|
|
@ -1373,6 +1389,14 @@ Koha::EDI
|
|||
Returns the Aqbudget object for the active budget given the passed budget_code
|
||||
or undefined if one does not exist
|
||||
|
||||
=head2 _handle_008_field
|
||||
|
||||
bib_record = _handle_008_field($bib_record)
|
||||
|
||||
Checks whether an 008 field exists on the record and adds a default field it does not
|
||||
|
||||
Returns the bib_record
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Colin Campbell <colin.campbell@ptfs-europe.com>
|
||||
|
|
|
|||
|
|
@ -180,8 +180,11 @@ sub harvest_sushi {
|
|||
$ua->agent( 'Koha/' . Koha::version() );
|
||||
my $response = $ua->simple_request($request);
|
||||
|
||||
my $result = decode_json( $response->decoded_content );
|
||||
|
||||
if ( $response->code >= 400 ) {
|
||||
my $result = decode_json( $response->decoded_content );
|
||||
|
||||
return if $self->_sushi_errors($result);
|
||||
|
||||
my $message;
|
||||
if ( ref($result) eq 'ARRAY' ) {
|
||||
|
|
@ -199,7 +202,6 @@ sub harvest_sushi {
|
|||
}
|
||||
}
|
||||
|
||||
#TODO: May want to add a job error message here?
|
||||
warn sprintf "ERROR - SUSHI service %s returned %s - %s\n", $url,
|
||||
$response->code, $message;
|
||||
if ( $response->code == 404 ) {
|
||||
|
|
@ -208,7 +210,6 @@ sub harvest_sushi {
|
|||
Koha::Exceptions::Authorization::Unauthorized->throw($message);
|
||||
} else {
|
||||
|
||||
#TODO: May want to add a job error message here?
|
||||
die sprintf "ERROR requesting SUSHI service\n%s\ncode %s: %s\n",
|
||||
$url, $response->code,
|
||||
$message;
|
||||
|
|
@ -217,12 +218,10 @@ sub harvest_sushi {
|
|||
return;
|
||||
}
|
||||
|
||||
my $decoded_response = decode_json( $response->decoded_content );
|
||||
|
||||
return if $self->_sushi_errors($decoded_response);
|
||||
return if $self->_sushi_errors($result);
|
||||
|
||||
# Parse the SUSHI response
|
||||
my $sushi_counter = Koha::ERM::EUsage::SushiCounter->new( { response => $decoded_response } );
|
||||
my $sushi_counter = Koha::ERM::EUsage::SushiCounter->new( { response => $result } );
|
||||
my $counter_file = $sushi_counter->get_COUNTER_from_SUSHI;
|
||||
|
||||
return if $self->_counter_file_size_too_large($counter_file);
|
||||
|
|
@ -399,6 +398,7 @@ sub _build_url_query {
|
|||
$url .= '&api_key=' . $self->api_key if $self->api_key;
|
||||
$url .= '&begin_date=' . substr $self->{begin_date}, 0, 7 if $self->{begin_date};
|
||||
$url .= '&end_date=' . substr $self->{end_date}, 0, 7 if $self->{end_date};
|
||||
$url .= '&platform=' . $self->service_platform if $self->service_platform;
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
|
@ -459,19 +459,24 @@ Additionally, adds background job report message(s) if that is the case
|
|||
sub _sushi_errors {
|
||||
my ( $self, $decoded_response ) = @_;
|
||||
|
||||
if ( $decoded_response->{Severity} ) {
|
||||
my $severity = $decoded_response->{Severity} // $decoded_response->{severity};
|
||||
my $message = $decoded_response->{Message} // $decoded_response->{message};
|
||||
my $code = $decoded_response->{Code} // $decoded_response->{code};
|
||||
|
||||
if ($severity) {
|
||||
$self->{job_callbacks}->{add_message_callback}->(
|
||||
{
|
||||
type => 'error',
|
||||
code => $decoded_response->{Code},
|
||||
message => $decoded_response->{Severity} . ' - ' . $decoded_response->{Message},
|
||||
code => $code,
|
||||
message => $severity . ' - ' . $message,
|
||||
}
|
||||
) if $self->{job_callbacks};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( $decoded_response->{Report_Header}->{Exceptions} ) {
|
||||
foreach my $exception ( @{ $decoded_response->{Report_Header}->{Exceptions} } ) {
|
||||
my $exceptions = $decoded_response->{Report_Header}->{Exceptions} // $decoded_response->{Exceptions};
|
||||
if ($exceptions) {
|
||||
foreach my $exception ( @{$exceptions} ) {
|
||||
$self->{job_callbacks}->{add_message_callback}->(
|
||||
{
|
||||
type => 'error',
|
||||
|
|
@ -483,7 +488,7 @@ sub _sushi_errors {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if ( scalar @{ $decoded_response->{Report_Items} } == 0 ) {
|
||||
if ( $decoded_response->{Report_Items} && scalar @{ $decoded_response->{Report_Items} } == 0 ) {
|
||||
$self->{job_callbacks}->{add_message_callback}->(
|
||||
{
|
||||
type => 'error',
|
||||
|
|
|
|||
|
|
@ -210,10 +210,10 @@ sub embed {
|
|||
|
||||
sub build_query_pagination {
|
||||
my ( $self, $params ) = @_;
|
||||
my $per_page = $params->{per_page}
|
||||
my $per_page = $params->{_per_page}
|
||||
// C4::Context->preference('RESTdefaultPageSize') // 20;
|
||||
if ( $per_page == -1 || $per_page > 100 ) { $per_page = 100; }
|
||||
my $page = $params->{page} || 1;
|
||||
my $page = $params->{_page} || 1;
|
||||
|
||||
return ( $per_page, $page );
|
||||
}
|
||||
|
|
|
|||
39
Koha/Hold.pm
39
Koha/Hold.pm
|
|
@ -34,7 +34,6 @@ use Koha::Biblios;
|
|||
use Koha::Hold::CancellationRequests;
|
||||
use Koha::Items;
|
||||
use Koha::Libraries;
|
||||
use Koha::Old::Holds;
|
||||
use Koha::Calendar;
|
||||
use Koha::Plugins;
|
||||
|
||||
|
|
@ -1014,6 +1013,7 @@ Move a hold to the old_reserve table following the same pattern as Koha::Patron-
|
|||
sub _move_to_old {
|
||||
my ($self) = @_;
|
||||
my $hold_infos = $self->unblessed;
|
||||
require Koha::Old::Hold;
|
||||
return Koha::Old::Hold->new( $hold_infos )->store;
|
||||
}
|
||||
|
||||
|
|
@ -1026,25 +1026,26 @@ on the API.
|
|||
|
||||
sub to_api_mapping {
|
||||
return {
|
||||
reserve_id => 'hold_id',
|
||||
borrowernumber => 'patron_id',
|
||||
reservedate => 'hold_date',
|
||||
biblionumber => 'biblio_id',
|
||||
branchcode => 'pickup_library_id',
|
||||
notificationdate => undef,
|
||||
reminderdate => undef,
|
||||
cancellationdate => 'cancellation_date',
|
||||
reservenotes => 'notes',
|
||||
found => 'status',
|
||||
itemnumber => 'item_id',
|
||||
waitingdate => 'waiting_date',
|
||||
expirationdate => 'expiration_date',
|
||||
reserve_id => 'hold_id',
|
||||
borrowernumber => 'patron_id',
|
||||
reservedate => 'hold_date',
|
||||
biblionumber => 'biblio_id',
|
||||
deleted_biblionumber => 'deleted_biblio_id',
|
||||
branchcode => 'pickup_library_id',
|
||||
notificationdate => undef,
|
||||
reminderdate => undef,
|
||||
cancellationdate => 'cancellation_date',
|
||||
reservenotes => 'notes',
|
||||
found => 'status',
|
||||
itemnumber => 'item_id',
|
||||
waitingdate => 'waiting_date',
|
||||
expirationdate => 'expiration_date',
|
||||
patron_expiration_date => undef,
|
||||
lowestPriority => 'lowest_priority',
|
||||
suspend => 'suspended',
|
||||
suspend_until => 'suspended_until',
|
||||
itemtype => 'item_type',
|
||||
item_level_hold => 'item_level',
|
||||
lowestPriority => 'lowest_priority',
|
||||
suspend => 'suspended',
|
||||
suspend_until => 'suspended_until',
|
||||
itemtype => 'item_type',
|
||||
item_level_hold => 'item_level',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -401,20 +401,23 @@ sub status {
|
|||
|
||||
my $backend_plugin = $self->get_backend_plugin($backend_name);
|
||||
|
||||
Returns the installed I<Koha::Plugin> corresponding to the given backend_id
|
||||
Returns the installed I<Koha::Plugin> corresponding to the given backend_id or undef if no plugin is found
|
||||
|
||||
=cut
|
||||
|
||||
sub get_backend_plugin {
|
||||
my ( $self, $backend_id ) = @_;
|
||||
|
||||
my @backend_plugins = Koha::Plugins->new()->GetPlugins(
|
||||
my $koha_plugins = Koha::Plugins->new();
|
||||
my @backend_plugins = $koha_plugins
|
||||
? Koha::Plugins->new()->GetPlugins(
|
||||
{
|
||||
method => 'ill_backend',
|
||||
metadata => { name => $backend_id },
|
||||
all => 1,
|
||||
}
|
||||
);
|
||||
)
|
||||
: ();
|
||||
|
||||
return $backend_plugins[0];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,14 +113,17 @@ Returns a list of names for all the installed ILL backend plugins.
|
|||
=cut
|
||||
|
||||
sub get_backend_plugin_names {
|
||||
my ( $self ) = @_;
|
||||
my ($self) = @_;
|
||||
|
||||
my @backend_plugins = Koha::Plugins->new()->GetPlugins(
|
||||
my $koha_plugins = Koha::Plugins->new();
|
||||
my @backend_plugins = $koha_plugins
|
||||
? $koha_plugins->GetPlugins(
|
||||
{
|
||||
method => 'ill_backend',
|
||||
all => 1
|
||||
}
|
||||
);
|
||||
)
|
||||
: ();
|
||||
|
||||
return map { $_->{metadata}->{name} } @backend_plugins;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ sub get_marc_record {
|
|||
$format = 'UNIMARCAUTH';
|
||||
}
|
||||
|
||||
my $record = MARC::Record->new_from_xml($self->marcxml, $self->encoding, $format);
|
||||
my $record = MARC::Record->new_from_xml( $self->marcxml, 'UTF-8', $format );
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -920,7 +920,7 @@ sub hidden_in_opac {
|
|||
|
||||
foreach my $field ( keys %{$rules} ) {
|
||||
|
||||
if ( any { $self->$field eq $_ } @{ $rules->{$field} } ) {
|
||||
if ( any { defined $self->$field && $self->$field eq $_ } @{ $rules->{$field} } ) {
|
||||
$hidden_in_opac = 1;
|
||||
last;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,10 +44,19 @@ sub call {
|
|||
my $request_method = $req->method // q{};
|
||||
my $uri = $req->uri // q{};
|
||||
my $referer = $req->referer // q{No referer};
|
||||
my $request_path = $req->path // q{};
|
||||
|
||||
my %path_exceptions = (
|
||||
'/ilsdi.pl' => 1,
|
||||
);
|
||||
|
||||
#NOTE: Ignore ErrorDocument requests for CSRF
|
||||
if ( $env->{'psgix.errordocument.SCRIPT_NAME'} ) {
|
||||
return $self->app->($env);
|
||||
} elsif ( $path_exceptions{$request_path} ) {
|
||||
|
||||
#NOTE: Ignore path exceptions for CSRF
|
||||
return $self->app->($env);
|
||||
}
|
||||
|
||||
my ($error);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package Koha::Number::Price;
|
|||
|
||||
use Modern::Perl;
|
||||
|
||||
use Math::BigFloat;
|
||||
use Number::Format;
|
||||
use C4::Context;
|
||||
use Koha::Acquisition::Currencies;
|
||||
|
|
@ -83,12 +84,7 @@ sub round {
|
|||
|
||||
my $format_params = $self->_format_params;
|
||||
|
||||
# To avoid the system to crash, we will not format big number
|
||||
# We divide per 100 because we want to keep the default DECIMAL_DIGITS (2)
|
||||
# error - round() overflow. Try smaller precision or use Math::BigFloat
|
||||
return $self->value if $self->value > Number::Format::MAX_INT/100;
|
||||
|
||||
return Number::Format->new(%$format_params)->round($self->value);
|
||||
return Number::Format->new(%$format_params)->round( Math::BigFloat->new( $self->value ) )->bdstr();
|
||||
}
|
||||
|
||||
sub _format_params {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use Modern::Perl;
|
|||
|
||||
use Koha::Database;
|
||||
use Koha::Exceptions;
|
||||
use Koha::Libraries;
|
||||
|
||||
use Try::Tiny qw( catch try );
|
||||
|
||||
|
|
@ -87,6 +86,8 @@ sub get_library_limits {
|
|||
|
||||
return unless @branchcodes;
|
||||
|
||||
require Koha::Libraries;
|
||||
|
||||
my $filter = [ map { { branchcode => $_ } } @branchcodes ];
|
||||
my $libraries = Koha::Libraries->search( $filter );
|
||||
|
||||
|
|
|
|||
|
|
@ -167,17 +167,19 @@ sub search_related {
|
|||
=cut
|
||||
|
||||
sub delete {
|
||||
my ($self) = @_;
|
||||
my ( $self, $params ) = @_;
|
||||
|
||||
if ( Class::Inspector->function_exists( $self->object_class, 'delete' ) ) {
|
||||
my $objects_deleted;
|
||||
$self->_resultset->result_source->schema->txn_do( sub {
|
||||
$self->reset; # If we iterated already over the set
|
||||
while ( my $o = $self->next ) {
|
||||
$o->delete;
|
||||
$objects_deleted++;
|
||||
$self->_resultset->result_source->schema->txn_do(
|
||||
sub {
|
||||
$self->reset; # If we iterated already over the set
|
||||
while ( my $o = $self->next ) {
|
||||
$o->delete($params);
|
||||
$objects_deleted++;
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
return $objects_deleted;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ package Koha::Patron;
|
|||
|
||||
use Modern::Perl;
|
||||
|
||||
use List::MoreUtils qw( any uniq );
|
||||
use List::MoreUtils qw( any none uniq );
|
||||
use JSON qw( to_json );
|
||||
use Unicode::Normalize qw( NFKD );
|
||||
use Try::Tiny;
|
||||
|
|
@ -315,7 +315,7 @@ sub store {
|
|||
}
|
||||
|
||||
foreach my $guarantor (@$guarantors) {
|
||||
if ( $guarantor->is_child or $guarantor->category->can_be_guarantee ) {
|
||||
if ( $guarantor->is_child ) {
|
||||
Koha::Exceptions::Patron::Relationship::InvalidRelationship->throw( invalid_guarantor => 1 );
|
||||
}
|
||||
}
|
||||
|
|
@ -372,7 +372,7 @@ sub store {
|
|||
}
|
||||
|
||||
foreach my $guarantor (@$guarantors) {
|
||||
if ( $guarantor->is_child or $guarantor->category->can_be_guarantee ) {
|
||||
if ( $guarantor->is_child ) {
|
||||
Koha::Exceptions::Patron::Relationship::InvalidRelationship->throw( invalid_guarantor => 1 );
|
||||
}
|
||||
}
|
||||
|
|
@ -443,7 +443,7 @@ sub delete {
|
|||
Koha::Exceptions::Patron::FailedDeleteAnonymousPatron->throw() if $anonymous_patron && $self->id eq $anonymous_patron;
|
||||
|
||||
# Check if patron is protected
|
||||
Koha::Exceptions::Patron::FailedDeleteProtectedPatron->throw() if $self->protected == 1;
|
||||
Koha::Exceptions::Patron::FailedDeleteProtectedPatron->throw() if defined $self->protected && $self->protected == 1;
|
||||
|
||||
$self->_result->result_source->schema->txn_do(
|
||||
sub {
|
||||
|
|
@ -499,7 +499,7 @@ Returns a Koha::Library object representing the patron's home library.
|
|||
|
||||
sub library {
|
||||
my ( $self ) = @_;
|
||||
return Koha::Library->_new_from_dbic($self->_result->branchcode);
|
||||
return Koha::Library->_new_from_dbic($self->_result->library);
|
||||
}
|
||||
|
||||
=head3 sms_provider
|
||||
|
|
@ -533,6 +533,18 @@ sub guarantor_relationships {
|
|||
return Koha::Patron::Relationships->search( { guarantee_id => $self->id } );
|
||||
}
|
||||
|
||||
=head3 is_guarantee
|
||||
|
||||
Returns true if the patron has a guarantor.
|
||||
|
||||
=cut
|
||||
|
||||
sub is_guarantee {
|
||||
my ($self) = @_;
|
||||
return $self->guarantor_relationships()->count();
|
||||
}
|
||||
|
||||
|
||||
=head3 guarantee_relationships
|
||||
|
||||
Returns Koha::Patron::Relationships object for this patron's guarantors
|
||||
|
|
@ -557,6 +569,18 @@ sub guarantee_relationships {
|
|||
);
|
||||
}
|
||||
|
||||
=head3 is_guarantor
|
||||
|
||||
Returns true if the patron is a guarantor.
|
||||
|
||||
=cut
|
||||
|
||||
sub is_guarantor {
|
||||
my ($self) = @_;
|
||||
return $self->guarantee_relationships()->count();
|
||||
}
|
||||
|
||||
|
||||
=head3 relationships_debt
|
||||
|
||||
Returns the amount owed by the patron's guarantors *and* the other guarantees of those guarantors
|
||||
|
|
@ -1527,6 +1551,7 @@ sub get_age {
|
|||
my $date_of_birth = dt_from_string( $self->dateofbirth, undef, 'floating' );
|
||||
my $today = dt_from_string(undef, undef, 'floating')->truncate( to => 'day' );
|
||||
|
||||
return 0 unless $date_of_birth;
|
||||
return $today->subtract_datetime( $date_of_birth )->years;
|
||||
}
|
||||
|
||||
|
|
@ -1584,6 +1609,7 @@ Return all the historical holds for this patron
|
|||
sub old_holds {
|
||||
my ($self) = @_;
|
||||
my $old_holds_rs = $self->_result->old_reserves->search( {}, { order_by => 'reservedate' } );
|
||||
require Koha::Old::Holds;
|
||||
return Koha::Old::Holds->_new_from_dbic($old_holds_rs);
|
||||
}
|
||||
|
||||
|
|
@ -1629,23 +1655,27 @@ sub return_claims {
|
|||
|
||||
=head3 notice_email_address
|
||||
|
||||
my $email = $patron->notice_email_address;
|
||||
my $email = $patron->notice_email_address;
|
||||
|
||||
Return the email address of patron used for notices.
|
||||
Returns the empty string if no email address.
|
||||
|
||||
=cut
|
||||
|
||||
sub notice_email_address{
|
||||
my ( $self ) = @_;
|
||||
sub notice_email_address {
|
||||
my ($self) = @_;
|
||||
|
||||
my $which_address = C4::Context->preference("EmailFieldPrimary");
|
||||
|
||||
# if syspref is set to 'first valid' (value == OFF), look up email address
|
||||
if ( $which_address eq 'OFF' ) {
|
||||
return $self->first_valid_email_address;
|
||||
if ( $which_address && ( none { $_ eq $which_address } qw{email emailpro B_email cardnumber MULTI} ) ) {
|
||||
warn "Invalid value for EmailFieldPrimary ($which_address)";
|
||||
$which_address = undef;
|
||||
}
|
||||
|
||||
# if syspref is set to 'first valid', look up email address
|
||||
return $self->first_valid_email_address
|
||||
unless $which_address;
|
||||
|
||||
# if syspref is set to 'selected addresses' (value == MULTI), look up email addresses
|
||||
if ( $which_address eq 'MULTI' ) {
|
||||
my @addresses;
|
||||
|
|
@ -1654,11 +1684,10 @@ sub notice_email_address{
|
|||
my $email_address = $self->$email_field;
|
||||
push @addresses, $email_address if $email_address;
|
||||
}
|
||||
return join(",",@addresses);
|
||||
return join( ",", @addresses );
|
||||
}
|
||||
|
||||
return $self->$which_address || '';
|
||||
|
||||
}
|
||||
|
||||
=head3 first_valid_email_address
|
||||
|
|
@ -2179,17 +2208,22 @@ sub extended_attributes {
|
|||
}
|
||||
|
||||
# Check globally mandatory types
|
||||
my @required_attribute_types =
|
||||
Koha::Patron::Attribute::Types->search(
|
||||
{
|
||||
mandatory => 1,
|
||||
category_code => [ undef, $self->categorycode ],
|
||||
'borrower_attribute_types_branches.b_branchcode' =>
|
||||
undef,
|
||||
},
|
||||
{ join => 'borrower_attribute_types_branches' }
|
||||
)->get_column('code');
|
||||
for my $type ( @required_attribute_types ) {
|
||||
my $interface = C4::Context->interface;
|
||||
my $params = {
|
||||
mandatory => 1,
|
||||
category_code => [ undef, $self->categorycode ],
|
||||
'borrower_attribute_types_branches.b_branchcode' => undef,
|
||||
};
|
||||
|
||||
if ( $interface eq 'opac' ) {
|
||||
$params->{opac_editable} = 1;
|
||||
}
|
||||
|
||||
my @required_attribute_types = Koha::Patron::Attribute::Types->search(
|
||||
$params,
|
||||
{ join => 'borrower_attribute_types_branches' }
|
||||
)->get_column('code');
|
||||
for my $type (@required_attribute_types) {
|
||||
Koha::Exceptions::Patron::MissingMandatoryExtendedAttribute->throw(
|
||||
type => $type,
|
||||
) if !$new_types->{$type};
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ sub store {
|
|||
Koha::Exceptions::Patron::Attribute::InvalidAttributeValue->throw( attribute => $self )
|
||||
unless $self->value_ok();
|
||||
|
||||
C4::Context->dbh->do(
|
||||
"UPDATE borrowers SET updated_on = NOW() WHERE borrowernumber = ?", undef,
|
||||
$self->borrowernumber
|
||||
);
|
||||
|
||||
return $self->SUPER::store();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ sub _validate_operator {
|
|||
my ($operator) = @_;
|
||||
my %allowed_operators =
|
||||
map { $_ => 1 }
|
||||
qw(= != < > <= >= -in -ident -bool -not_bool -or like -like -not_like -between -not_between -not -and -regexp);
|
||||
qw(= != < > <= >= -in -ident -bool -not_bool -or like -like -not_like -between -not_between -not -and -regexp -not_in);
|
||||
Koha::Exceptions::REST::Query::InvalidOperator->throw( operator => $operator )
|
||||
unless exists $allowed_operators{$operator};
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ sub list {
|
|||
my $c = shift->openapi->valid_input or return;
|
||||
|
||||
return try {
|
||||
my $authorised_value_categories_set = Koha::AuthorisedValueCategories->new;
|
||||
my $authorised_value_categories = $c->objects->search( $authorised_value_categories_set );
|
||||
my $authorised_value_categories_set =
|
||||
Koha::AuthorisedValueCategories->search( {}, { order_by => 'category_name' } );
|
||||
my $authorised_value_categories = $c->objects->search($authorised_value_categories_set);
|
||||
return $c->render( status => 200, openapi => $authorised_value_categories );
|
||||
}
|
||||
catch {
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ sub _check_availability {
|
|||
|
||||
# Upgrade some confirmations to blockers
|
||||
my @should_block =
|
||||
qw/TOO_MANY ISSUED_TO_ANOTHER RESERVED RESERVED_WAITING TRANSFERRED PROCESSING AGE_RESTRICTION/;
|
||||
qw/TOO_MANY ISSUED_TO_ANOTHER RESERVED RESERVE_WAITING TRANSFERRED PROCESSING AGE_RESTRICTION/;
|
||||
for my $block (@should_block) {
|
||||
if ( exists( $confirmation->{$block} ) ) {
|
||||
$impossible->{$block} = $confirmation->{$block};
|
||||
|
|
|
|||
|
|
@ -35,12 +35,7 @@ sub list {
|
|||
my $result = $ebsco->request( GET => '/packages' . $params );
|
||||
my $base_total = $result->{totalResults};
|
||||
|
||||
my ( $per_page, $page ) = $ebsco->build_query_pagination(
|
||||
{
|
||||
per_page => $c->stash('koha.pagination.per_page'),
|
||||
page => $c->stash('koha.pagination.page'),
|
||||
}
|
||||
);
|
||||
my ( $per_page, $page ) = $ebsco->build_query_pagination( $c->req->params->to_hash );
|
||||
my $additional_params =
|
||||
$ebsco->build_additional_params( $c->req->params->to_hash );
|
||||
|
||||
|
|
|
|||
|
|
@ -73,12 +73,7 @@ sub list {
|
|||
|
||||
my $base_total = $result->{totalResults};
|
||||
|
||||
my ( $per_page, $page ) = $ebsco->build_query_pagination(
|
||||
{
|
||||
per_page => $c->stash('koha.pagination.per_page'),
|
||||
page => $c->stash('koha.pagination.page'),
|
||||
}
|
||||
);
|
||||
my ( $per_page, $page ) = $ebsco->build_query_pagination( $c->req->params->to_hash );
|
||||
|
||||
my $additional_params = $ebsco->build_additional_params( $c->req->params->to_hash );
|
||||
my $searchfield = 'titlename';
|
||||
|
|
|
|||
|
|
@ -41,12 +41,7 @@ sub list {
|
|||
my $ebsco = Koha::ERM::Providers::EBSCO->new;
|
||||
|
||||
# We cannot get base_total as a search kw is required by the API
|
||||
my ( $per_page, $page ) = $ebsco->build_query_pagination(
|
||||
{
|
||||
per_page => $c->stash('koha.pagination.per_page'),
|
||||
page => $c->stash('koha.pagination.page'),
|
||||
}
|
||||
);
|
||||
my ( $per_page, $page ) = $ebsco->build_query_pagination( $c->req->params->to_hash );
|
||||
|
||||
my $additional_params = $ebsco->build_additional_params( $c->req->params->to_hash );
|
||||
|
||||
|
|
|
|||
|
|
@ -207,14 +207,14 @@ sub add_debit {
|
|||
my $c = shift->openapi->valid_input or return;
|
||||
|
||||
my $patron = Koha::Patrons->find( $c->param('patron_id') );
|
||||
my $user = $c->stash('koha.user');
|
||||
|
||||
return $c->render_resource_not_found("Patron")
|
||||
unless $patron;
|
||||
unless $patron;
|
||||
|
||||
return try {
|
||||
my $data =
|
||||
Koha::Account::Debit->new_from_api( $c->req->json )
|
||||
->unblessed;
|
||||
Koha::Account::Debit->new_from_api( $c->req->json )->unblessed;
|
||||
|
||||
$data->{library_id} = delete $data->{branchcode};
|
||||
$data->{type} = delete $data->{debit_type_code};
|
||||
|
|
@ -223,11 +223,10 @@ sub add_debit {
|
|||
$data->{transaction_type} = delete $data->{payment_type};
|
||||
$data->{interface} = 'api'
|
||||
; # Should this always be API, or should we allow the API consumer to choose?
|
||||
$data->{user_id} = $patron->borrowernumber
|
||||
; # Should this be API user OR staff the API may be acting on behalf of?
|
||||
$data->{user_id} = delete $data->{manager_id} || $user->id;
|
||||
|
||||
my $debit = $patron->account->add_debit($data);
|
||||
$debit = Koha::Account::Debit->_new_from_dbic($debit->{_result});
|
||||
$debit = Koha::Account::Debit->_new_from_dbic( $debit->{_result} );
|
||||
|
||||
$c->res->headers->location(
|
||||
$c->req->url->to_string . '/' . $debit->id );
|
||||
|
|
@ -248,13 +247,13 @@ sub add_debit {
|
|||
}
|
||||
elsif ( $_->isa('Koha::Exceptions::Account::AmountNotPositive') ) {
|
||||
return $c->render(
|
||||
status => 400,
|
||||
status => 400,
|
||||
openapi => { error => $_->description }
|
||||
);
|
||||
}
|
||||
elsif ( $_->isa('Koha::Exceptions::Account::UnrecognisedType') ) {
|
||||
return $c->render(
|
||||
status => 400,
|
||||
status => 400,
|
||||
openapi => { error => $_->description }
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,12 +55,8 @@ sub get {
|
|||
|
||||
return try {
|
||||
my $source = $c->objects->find( Koha::RecordSources->new, $c->param('record_source_id') );
|
||||
unless ($source) {
|
||||
return $c->render(
|
||||
status => 404,
|
||||
openapi => { error => "Object not found" }
|
||||
);
|
||||
}
|
||||
return $c->render_resource_not_found("Record source")
|
||||
unless $source;
|
||||
|
||||
return $c->render( status => 200, openapi => $source );
|
||||
} catch {
|
||||
|
|
@ -97,12 +93,8 @@ sub update {
|
|||
|
||||
my $source = $c->objects->find_rs( Koha::RecordSources->new, $c->param('record_source_id') );
|
||||
|
||||
unless ($source) {
|
||||
return $c->render(
|
||||
status => 404,
|
||||
openapi => { error => "Object not found" }
|
||||
);
|
||||
}
|
||||
return $c->render_resource_not_found("Record source")
|
||||
unless $source;
|
||||
|
||||
return try {
|
||||
$source->set_from_api( $c->req->json )->store;
|
||||
|
|
@ -122,19 +114,12 @@ sub delete {
|
|||
|
||||
my $source = $c->objects->find_rs( Koha::RecordSources->new, $c->param('record_source_id') );
|
||||
|
||||
unless ($source) {
|
||||
return $c->render(
|
||||
status => 404,
|
||||
openapi => { error => "Object not found" }
|
||||
);
|
||||
}
|
||||
return $c->render_resource_not_found("Record source")
|
||||
unless $source;
|
||||
|
||||
return try {
|
||||
$source->delete;
|
||||
return $c->render(
|
||||
status => 204,
|
||||
openapi => q{}
|
||||
);
|
||||
return $c->render_resource_deleted;
|
||||
} catch {
|
||||
$c->unhandled_exception($_);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2191,6 +2191,13 @@ __PACKAGE__->many_to_many("permissions", "user_permissions", "permission");
|
|||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-05-02 11:36:36
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jUOMoSonNmA3KwtZKVxqOA
|
||||
|
||||
__PACKAGE__->belongs_to(
|
||||
"library",
|
||||
"Koha::Schema::Result::Branch",
|
||||
{ branchcode => "branchcode" },
|
||||
{ is_deferrable => 1, on_delete => "RESTRICT", on_update => "RESTRICT" },
|
||||
);
|
||||
|
||||
__PACKAGE__->has_many(
|
||||
"restrictions",
|
||||
"Koha::Schema::Result::BorrowerDebarment",
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ item barcode (MARC21 952$p)
|
|||
default_value: 0
|
||||
is_nullable: 0
|
||||
|
||||
boolean value defining whether this item is available for bookings or not
|
||||
boolean value defining whether this this item is available for bookings or not
|
||||
|
||||
=head2 dateaccessioned
|
||||
|
||||
|
|
|
|||
|
|
@ -88,9 +88,8 @@ priority of the renewal
|
|||
|
||||
=head2 license_info
|
||||
|
||||
data_type: 'varchar'
|
||||
data_type: 'mediumtext'
|
||||
is_nullable: 1
|
||||
size: 80
|
||||
|
||||
info about the license
|
||||
|
||||
|
|
@ -114,7 +113,7 @@ __PACKAGE__->add_columns(
|
|||
"renewal_priority",
|
||||
{ data_type => "varchar", is_nullable => 1, size => 80 },
|
||||
"license_info",
|
||||
{ data_type => "varchar", is_nullable => 1, size => 80 },
|
||||
{ data_type => "mediumtext", is_nullable => 1 },
|
||||
);
|
||||
|
||||
=head1 PRIMARY KEY
|
||||
|
|
@ -267,8 +266,8 @@ Composing rels: L</erm_eholdings_packages_agreements> -> package
|
|||
__PACKAGE__->many_to_many("packages", "erm_eholdings_packages_agreements", "package");
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-11-11 11:52:09
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:N93LnvdKirtuV6BSrTGzVg
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-17 23:37:27
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:lc0DnoQ5ai9sVBjczw6FdQ
|
||||
|
||||
__PACKAGE__->has_many(
|
||||
"user_roles",
|
||||
|
|
|
|||
|
|
@ -142,6 +142,14 @@ requestor email
|
|||
|
||||
report types provided by the harvester
|
||||
|
||||
=head2 service_platform
|
||||
|
||||
data_type: 'varchar'
|
||||
is_nullable: 1
|
||||
size: 80
|
||||
|
||||
platform if provider requires it
|
||||
|
||||
=cut
|
||||
|
||||
__PACKAGE__->add_columns(
|
||||
|
|
@ -175,6 +183,8 @@ __PACKAGE__->add_columns(
|
|||
{ data_type => "varchar", is_nullable => 1, size => 80 },
|
||||
"report_types",
|
||||
{ data_type => "varchar", is_nullable => 1, size => 255 },
|
||||
"service_platform",
|
||||
{ data_type => "varchar", is_nullable => 1, size => 80 },
|
||||
);
|
||||
|
||||
=head1 PRIMARY KEY
|
||||
|
|
@ -328,8 +338,8 @@ __PACKAGE__->has_many(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-10-11 10:09:06
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:MSvyv/Abt3S3fqZF21v/7w
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-05 19:06:48
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VzC6luzfNA1QBZ7slRs6OQ
|
||||
|
||||
# __PACKAGE__->add_columns(
|
||||
# '+active' => { is_boolean => 1 }
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ item barcode (MARC21 952$p)
|
|||
default_value: 0
|
||||
is_nullable: 0
|
||||
|
||||
boolean value defining whether this item is available for bookings or not
|
||||
boolean value defining whether this this item is available for bookings or not
|
||||
|
||||
=head2 dateaccessioned
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,13 @@ the date the hold was places
|
|||
|
||||
foreign key from the biblio table defining which bib record this hold is on
|
||||
|
||||
=head2 deleted_biblionumber
|
||||
|
||||
data_type: 'integer'
|
||||
is_nullable: 1
|
||||
|
||||
links the hold to the deleted bibliographic record (deletedbiblio.biblionumber)
|
||||
|
||||
=head2 item_group_id
|
||||
|
||||
data_type: 'integer'
|
||||
|
|
@ -235,6 +242,8 @@ __PACKAGE__->add_columns(
|
|||
{ data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 },
|
||||
"biblionumber",
|
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
|
||||
"deleted_biblionumber",
|
||||
{ data_type => "integer", is_nullable => 1 },
|
||||
"item_group_id",
|
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
|
||||
"branchcode",
|
||||
|
|
@ -428,8 +437,8 @@ __PACKAGE__->belongs_to(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2024-04-05 06:44:57
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SQp2OEYb3im1x3A+W0h37w
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-05 19:06:48
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:7mO1W8tdYtEk7pijJuxsMA
|
||||
|
||||
__PACKAGE__->belongs_to(
|
||||
"item",
|
||||
|
|
|
|||
|
|
@ -57,6 +57,13 @@ the date the hold was placed
|
|||
|
||||
foreign key from the biblio table defining which bib record this hold is on
|
||||
|
||||
=head2 deleted_biblionumber
|
||||
|
||||
data_type: 'integer'
|
||||
is_nullable: 1
|
||||
|
||||
links the hold to the deleted bibliographic record (deletedbiblio.biblionumber)
|
||||
|
||||
=head2 item_group_id
|
||||
|
||||
data_type: 'integer'
|
||||
|
|
@ -243,6 +250,8 @@ __PACKAGE__->add_columns(
|
|||
is_foreign_key => 1,
|
||||
is_nullable => 0,
|
||||
},
|
||||
"deleted_biblionumber",
|
||||
{ data_type => "integer", is_nullable => 1 },
|
||||
"item_group_id",
|
||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
|
||||
"branchcode",
|
||||
|
|
@ -456,8 +465,8 @@ __PACKAGE__->belongs_to(
|
|||
);
|
||||
|
||||
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-11-01 18:21:38
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:6BAjuPSwjtyWJaJN9fcOtg
|
||||
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-05 19:06:48
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:OU6N7F+5LfbGfkhJMv53GA
|
||||
|
||||
__PACKAGE__->belongs_to(
|
||||
"item",
|
||||
|
|
|
|||
|
|
@ -790,7 +790,20 @@ sub marc_records_to_documents {
|
|||
local $SIG{__WARN__} = sub {
|
||||
push @warnings, $_[0];
|
||||
};
|
||||
$record_document->{'marc_data'} = encode_base64(encode('UTF-8', $record->as_usmarc()));
|
||||
my $usmarc_record = $record->as_usmarc();
|
||||
|
||||
#NOTE: Try to round-trip the record to prove it will work for retrieval after searching
|
||||
my $decoded_usmarc_record = MARC::Record->new_from_usmarc($usmarc_record);
|
||||
if ( $decoded_usmarc_record->warnings() ) {
|
||||
|
||||
#NOTE: We override the warnings since they're many and misleading
|
||||
@warnings = (
|
||||
"Warnings encountered while roundtripping a MARC record to/from USMARC. Failing over to MARCXML.",
|
||||
);
|
||||
}
|
||||
|
||||
my $marc_data = encode_base64( encode( 'UTF-8', $usmarc_record ) );
|
||||
$record_document->{'marc_data'} = $marc_data;
|
||||
}
|
||||
if (@warnings) {
|
||||
# Suppress warnings if record length exceeded
|
||||
|
|
|
|||
|
|
@ -248,6 +248,20 @@ sub search_auth_compat {
|
|||
$result{authtype} = $authtype ? $authtype->authtypetext : $authtypecode;
|
||||
$result{reported_tag} = $reported_tag;
|
||||
|
||||
if ( C4::Context->preference('ShowHeadingUse') ) {
|
||||
# checking valid heading use
|
||||
my $f008 = $marc->field('008');
|
||||
if ($f008) {
|
||||
my $pos14to16 = substr( $f008->data, 14, 3 );
|
||||
my $main = substr( $pos14to16, 0, 1 );
|
||||
$result{main} = 1 if $main eq 'a';
|
||||
my $subject = substr( $pos14to16, 1, 1 );
|
||||
$result{subject} = 1 if $subject eq 'a';
|
||||
my $series = substr( $pos14to16, 2, 1 );
|
||||
$result{series} = 1 if $series eq 'a';
|
||||
}
|
||||
}
|
||||
|
||||
# Reimplementing BuildSummary is out of scope because it'll be hard
|
||||
$result{summary} =
|
||||
C4::AuthoritiesMarc::BuildSummary( $marc, $result{authid},
|
||||
|
|
@ -497,7 +511,7 @@ sub _convert_facets {
|
|||
push @{ $facet->{facets} }, {
|
||||
facet_count => $c,
|
||||
facet_link_value => $t,
|
||||
facet_title_value => $t . " ($c)",
|
||||
facet_title_value => $t,
|
||||
facet_label_value => $label, # TODO either truncate this,
|
||||
# or make the template do it like it should anyway
|
||||
type_link_value => $type,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ sub expand_filter {
|
|||
my $operands = $query->{operands};
|
||||
my $indexes = $query->{indexes};
|
||||
|
||||
my $query_limit;
|
||||
my $query_limit = "(";
|
||||
for( my $i = 0; $i < scalar @$operands; $i++ ){
|
||||
next unless @$operands[$i];
|
||||
my $index = @$indexes[$i] ? @$indexes[$i] . "=" : "";
|
||||
|
|
@ -61,6 +61,7 @@ sub expand_filter {
|
|||
my $limit = $operator . $index . $query;
|
||||
$query_limit .= $limit;
|
||||
}
|
||||
$query_limit .= ")";
|
||||
|
||||
return ($limits, $query_limit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,14 @@ sub pseudonymize {
|
|||
my ($self) = @_;
|
||||
|
||||
return unless ( $self->borrowernumber && grep { $_ eq $self->type } qw(renew issue return onsite_checkout) );
|
||||
Koha::BackgroundJob::PseudonymizeStatistic->new->enqueue( { statistic => $self->unblessed } );
|
||||
|
||||
# FIXME When getting the object from svc/renewal we get a DateTime object
|
||||
# normally we just fetch from DB to clear this, but statistics has no primary key
|
||||
# so we just force it to string context
|
||||
my $unblessed = $self->unblessed;
|
||||
$unblessed->{datetime} = $unblessed->{datetime} . "";
|
||||
|
||||
Koha::BackgroundJob::PseudonymizeStatistic->new->enqueue( { statistic => $unblessed } );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,10 +40,11 @@ sub get {
|
|||
|
||||
my $content = Koha::AdditionalContents->search_for_display(
|
||||
{
|
||||
category => $category,
|
||||
location => $location,
|
||||
lang => $lang,
|
||||
category => $category,
|
||||
location => $location,
|
||||
lang => $lang,
|
||||
( $library ? ( library_id => $library ) : () ),
|
||||
( $id ? ( id => $id ) : () ),
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
package Koha::Template::Plugin::SafeURL;
|
||||
|
||||
# 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 URI;
|
||||
use base 'Template::Plugin::Filter';
|
||||
|
||||
sub init {
|
||||
my $self = shift;
|
||||
my $name = 'safe_url';
|
||||
$self->{_DYNAMIC} = 1;
|
||||
$self->install_filter($name);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub filter {
|
||||
my ( $self, $text, $args, $config ) = @_;
|
||||
my $uri = URI->new($text);
|
||||
if ($uri) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
#NOTE: If it isn't a real URL, just return a safe fragment
|
||||
return '#';
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Koha::Template::Plugin::SafeURL - TT Plugin for filtering whole URLs
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
[% USE SafeURL %]
|
||||
|
||||
[% $url | safe_url %]
|
||||
|
||||
This filter parses the text as a URL and returns the object which
|
||||
is stringified in a safe format.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 init
|
||||
|
||||
This method installs the filter name and declares it as a dynamic filter
|
||||
|
||||
=head2 filter
|
||||
|
||||
Returns a stringified version of a Perl URL object
|
||||
|
||||
=cut
|
||||
|
|
@ -361,10 +361,13 @@ sub build_authorized_values_list {
|
|||
}
|
||||
}
|
||||
|
||||
my $id_subfield = $subfield;
|
||||
$id_subfield = "00" if $id_subfield eq "@";
|
||||
|
||||
return {
|
||||
type => 'select',
|
||||
id => "tag_".$tag."_subfield_".$subfield."_".$index_tag."_".$index_subfield,
|
||||
name => "tag_".$tag."_subfield_".$subfield."_".$index_tag."_".$index_subfield,
|
||||
id => "tag_".$tag."_subfield_".$id_subfield."_".$index_tag."_".$index_subfield,
|
||||
name => "tag_".$tag."_subfield_".$id_subfield."_".$index_tag."_".$index_subfield,
|
||||
default => $value,
|
||||
values => \@authorised_values,
|
||||
labels => \%authorised_lib,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ sub createMergeHash {
|
|||
(
|
||||
!defined($tagslib) || ( defined $tagslib->{$fieldtag}
|
||||
&& defined $tagslib->{$fieldtag}->{'tab'}
|
||||
&& $tagslib->{$fieldtag}->{'tab'} >= 0 )
|
||||
&& ( $tagslib->{$fieldtag}->{'tab'} ? $tagslib->{$fieldtag}->{'tab'} : 0 ) >= 0 )
|
||||
)
|
||||
&& @subfield_array
|
||||
)
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ my $target_map = {
|
|||
'cypress.config.ts' => 'NONE',
|
||||
'tsconfig.json' => 'NONE',
|
||||
'webpack.config.js' => 'NONE',
|
||||
'rspack.config.js' => 'NONE',
|
||||
};
|
||||
|
||||
=head1 CONFIGURATION OPTIONS
|
||||
|
|
@ -673,9 +674,7 @@ $file_map->{'koha-tmpl/intranet-tmpl/prog/css/installer.css'} = 'blib/INTRANET_T
|
|||
$file_map->{'koha-tmpl/intranet-tmpl/prog/css/mainpage.css'} = 'blib/INTRANET_TMPL_DIR/prog/css/mainpage.css';
|
||||
$file_map->{'koha-tmpl/intranet-tmpl/prog/css/staff-global.css'} = 'blib/INTRANET_TMPL_DIR/prog/css/staff-global.css';
|
||||
$file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/erm.js'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/erm.js';
|
||||
$file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/erm.js.LICENSE.txt'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/erm.js.LICENSE.txt';
|
||||
$file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/preservation.js'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/preservation.js';
|
||||
$file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/preservation.js.LICENSE.txt'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/preservation.js.LICENSE.txt';
|
||||
#OPAC_TMPL_DIR
|
||||
$file_map->{'koha-tmpl/opac-tmpl/bootstrap/css/opac.css'} = 'blib/OPAC_TMPL_DIR/bootstrap/css/opac.css';
|
||||
$file_map->{'koha-tmpl/opac-tmpl/bootstrap/css/opac-rtl.css'} = 'blib/OPAC_TMPL_DIR/bootstrap/css/opac-rtl.css';
|
||||
|
|
|
|||
|
|
@ -532,10 +532,9 @@ sub import_biblios_list {
|
|||
my $quantity = delete $iteminfos->{quantity} || 1;
|
||||
|
||||
# Handle incorrectly named original parameters for MarcItemFieldsToOrder
|
||||
$iteminfos->{location} = delete $iteminfos->{loc} if $iteminfos->{loc};
|
||||
$iteminfos->{copynumber} = delete $iteminfos->{copyno} if $iteminfos->{copyno};
|
||||
$iteminfos->{location} = delete $iteminfos->{loc} if $iteminfos->{loc};
|
||||
# Price is handled as "itemprice" in the UI form to distinguish from MarcFieldsToOrder
|
||||
$iteminfos->{itemprice} = delete $iteminfos->{price} if $iteminfos->{itemprice};
|
||||
$iteminfos->{itemprice} = delete $iteminfos->{price} if $iteminfos->{itemprice};
|
||||
|
||||
# Convert budge code to a budget id
|
||||
my $item_budget_code = delete $iteminfos->{budget_code};
|
||||
|
|
|
|||
|
|
@ -169,15 +169,16 @@ my @gst_values = map {
|
|||
}, split( '\|', C4::Context->preference("TaxRates") );
|
||||
|
||||
$template->param(
|
||||
freight => $freight,
|
||||
name => $bookseller->name,
|
||||
active_currency => $active_currency,
|
||||
currencies => $currencies->search({ rate => { '!=' => 1 } }),
|
||||
invoiceincgst => $bookseller->invoiceincgst,
|
||||
invoiceid => $invoice->{invoiceid},
|
||||
invoice => $invoice->{invoicenumber},
|
||||
gst_values => \@gst_values,
|
||||
vendor => $bookseller,
|
||||
freight => $freight,
|
||||
name => $bookseller->name,
|
||||
active_currency => $active_currency,
|
||||
currencies => $currencies->search( { rate => { '!=' => 1 } } ),
|
||||
invoiceincgst => $bookseller->invoiceincgst,
|
||||
invoiceid => $invoice->{invoiceid},
|
||||
invoice => $invoice->{invoicenumber},
|
||||
gst_values => \@gst_values,
|
||||
vendor => $bookseller,
|
||||
UniqueItemFields => C4::Context->preference('UniqueItemFields'),
|
||||
);
|
||||
|
||||
my $patron = Koha::Patrons->find( $loggedinuser )->unblessed;
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ if ( $op eq 'add_form' ) {
|
|||
#ADD_VALIDATE: called by add_form, used to insert/modify data in DB
|
||||
elsif ( $op eq 'cud-add_validate' ) {
|
||||
## Please see file perltidy.ERR
|
||||
$template->param( add_validate => 1 );
|
||||
|
||||
my $is_a_modif = $input->param("is_a_modif");
|
||||
|
||||
|
|
|
|||
|
|
@ -119,19 +119,8 @@ my $budgets_ref = GetBudgetHierarchy(
|
|||
);
|
||||
|
||||
# build categories list
|
||||
my $sth = $dbh->prepare("select distinct category from authorised_values where category like 'A%' ");
|
||||
$sth->execute;
|
||||
|
||||
# the list
|
||||
my @category_list;
|
||||
|
||||
# a hash, to check that some hardcoded categories exist.
|
||||
my %categories;
|
||||
while ( my ($category) = $sth->fetchrow_array ) {
|
||||
push( @category_list, $category );
|
||||
$categories{$category} = 1;
|
||||
}
|
||||
|
||||
# push koha system categories
|
||||
push( @category_list, 'MONTHS' );
|
||||
push( @category_list, 'ITEMTYPES' );
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ modules:
|
|||
-
|
||||
columnname: holdings_datelastborrowed
|
||||
-
|
||||
columnname: holdings_barcodes
|
||||
columnname: holdings_barcode
|
||||
-
|
||||
columnname: holdings_uri
|
||||
-
|
||||
|
|
@ -2026,6 +2026,20 @@ modules:
|
|||
-
|
||||
columnname: item_coursereserves
|
||||
|
||||
subscriptionst:
|
||||
columns:
|
||||
-
|
||||
columnname: serial_serialseq
|
||||
-
|
||||
columnname: serial_publisheddate
|
||||
-
|
||||
columnname: serial_planneddate
|
||||
-
|
||||
columnname: serial_status
|
||||
-
|
||||
columnname: serial_notes
|
||||
|
||||
course_list:
|
||||
course_reserves_table:
|
||||
columns:
|
||||
-
|
||||
|
|
@ -2043,19 +2057,7 @@ modules:
|
|||
-
|
||||
columnname: notes
|
||||
|
||||
subscriptionst:
|
||||
columns:
|
||||
-
|
||||
columnname: serial_serialseq
|
||||
-
|
||||
columnname: serial_publisheddate
|
||||
-
|
||||
columnname: serial_planneddate
|
||||
-
|
||||
columnname: serial_status
|
||||
-
|
||||
columnname: serial_notes
|
||||
|
||||
course_items:
|
||||
course-items-table:
|
||||
columns:
|
||||
-
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use C4::Context;
|
|||
use Koha::Caches;
|
||||
use Koha::AuthorisedValues;
|
||||
use Koha::BiblioFrameworks;
|
||||
use Koha::Database;
|
||||
|
||||
# retrieve parameters
|
||||
my $input = CGI->new;
|
||||
|
|
@ -120,6 +121,7 @@ if ($op eq 'add_form') {
|
|||
my $authorised_value = $input->param('authorised_value');
|
||||
my $ind1_defaultvalue = $input->param('ind1_defaultvalue');
|
||||
my $ind2_defaultvalue = $input->param('ind2_defaultvalue');
|
||||
my $error;
|
||||
if ($input->param('modif')) {
|
||||
$sth = $dbh->prepare(
|
||||
"UPDATE marc_tag_structure SET liblibrarian=? ,libopac=? ,repeatable=? ,mandatory=? ,important=? ,authorised_value=?, ind1_defaultvalue=?, ind2_defaultvalue=? WHERE frameworkcode=? AND tagfield=?"
|
||||
|
|
@ -136,26 +138,40 @@ if ($op eq 'add_form') {
|
|||
$tagfield
|
||||
);
|
||||
} else {
|
||||
$sth = $dbh->prepare(
|
||||
"INSERT INTO marc_tag_structure (tagfield,liblibrarian,libopac,repeatable,mandatory,important,authorised_value,ind1_defaultvalue,ind2_defaultvalue,frameworkcode) values (?,?,?,?,?,?,?,?,?,?)"
|
||||
);
|
||||
$sth->execute($tagfield,
|
||||
$liblibrarian,
|
||||
$libopac,
|
||||
$repeatable,
|
||||
$mandatory,
|
||||
$important,
|
||||
$authorised_value,
|
||||
$ind1_defaultvalue,
|
||||
$ind2_defaultvalue,
|
||||
$frameworkcode
|
||||
);
|
||||
my $schema = Koha::Database->new()->schema();
|
||||
my $rs = $schema->resultset('MarcTagStructure');
|
||||
my $field = $rs->find( { tagfield => $tagfield, frameworkcode => $frameworkcode } );
|
||||
if ( !$field ) {
|
||||
$sth = $dbh->prepare(
|
||||
"INSERT INTO marc_tag_structure (tagfield,liblibrarian,libopac,repeatable,mandatory,important,authorised_value,ind1_defaultvalue,ind2_defaultvalue,frameworkcode) values (?,?,?,?,?,?,?,?,?,?)"
|
||||
);
|
||||
$sth->execute(
|
||||
$tagfield,
|
||||
$liblibrarian,
|
||||
$libopac,
|
||||
$repeatable,
|
||||
$mandatory,
|
||||
$important,
|
||||
$authorised_value,
|
||||
$ind1_defaultvalue,
|
||||
$ind2_defaultvalue,
|
||||
$frameworkcode
|
||||
);
|
||||
} else {
|
||||
$error = 'duplicate_tagfield';
|
||||
}
|
||||
}
|
||||
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
|
||||
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
|
||||
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
|
||||
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
|
||||
print $input->redirect("/cgi-bin/koha/admin/marctagstructure.pl?searchfield=$tagfield&frameworkcode=$frameworkcode");
|
||||
if ( !$error ) {
|
||||
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
|
||||
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
|
||||
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
|
||||
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
|
||||
}
|
||||
my $redirect_url = "/cgi-bin/koha/admin/marctagstructure.pl?searchfield=$tagfield&frameworkcode=$frameworkcode";
|
||||
if ($error) {
|
||||
$redirect_url .= "&error=$error";
|
||||
}
|
||||
print $input->redirect($redirect_url);
|
||||
exit;
|
||||
# END $OP eq ADD_VALIDATE
|
||||
################## DELETE_CONFIRM ##################################
|
||||
|
|
@ -200,6 +216,12 @@ if ($op eq 'add_form') {
|
|||
|
||||
################## DEFAULT ##################################
|
||||
} else { # DEFAULT
|
||||
my $error_code = $input->param('error');
|
||||
if ($error_code){
|
||||
if ($error_code eq 'duplicate_tagfield'){
|
||||
$template->param('blocking_error' => $error_code);
|
||||
}
|
||||
}
|
||||
# here, $op can be unset or set to "cud-framework_create_confirm".
|
||||
if ($searchfield ne '') {
|
||||
$template->param(searchfield => $searchfield);
|
||||
|
|
|
|||
|
|
@ -3125,21 +3125,6 @@ biblios:
|
|||
marc_type: marc21
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: 752ad
|
||||
marc_type: marc21
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: 210a
|
||||
marc_type: unimarc
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: 214a
|
||||
marc_type: unimarc
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
opac: 1
|
||||
staff_client: 1
|
||||
type: ''
|
||||
|
|
@ -3194,6 +3179,21 @@ biblios:
|
|||
marc_type: marc21
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: 752ad
|
||||
marc_type: marc21
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: 210a
|
||||
marc_type: unimarc
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: 214a
|
||||
marc_type: unimarc
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
opac: 1
|
||||
staff_client: 1
|
||||
type: ''
|
||||
|
|
@ -3768,7 +3768,7 @@ biblios:
|
|||
sort: 1
|
||||
suggestible: 1
|
||||
- facet: ''
|
||||
marc_field: '246'
|
||||
marc_field: 246abnp
|
||||
marc_type: marc21
|
||||
sort: 0
|
||||
suggestible: 1
|
||||
|
|
@ -4143,7 +4143,7 @@ biblios:
|
|||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: '246'
|
||||
marc_field: 246abnp
|
||||
marc_type: marc21
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
|
|
@ -4184,7 +4184,7 @@ biblios:
|
|||
sort: 1
|
||||
suggestible: ''
|
||||
- facet: ''
|
||||
marc_field: '246'
|
||||
marc_field: 246abnp
|
||||
marc_type: marc21
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
|
|
@ -4196,7 +4196,7 @@ biblios:
|
|||
mandatory: ~
|
||||
mappings:
|
||||
- facet: ''
|
||||
marc_field: '246'
|
||||
marc_field: 246abnp
|
||||
marc_type: marc21
|
||||
sort: 1
|
||||
suggestible: ''
|
||||
|
|
|
|||
|
|
@ -73,6 +73,11 @@ properties:
|
|||
type:
|
||||
- string
|
||||
- "null"
|
||||
service_platform:
|
||||
description: service platform of the harvester
|
||||
type:
|
||||
- string
|
||||
- "null"
|
||||
metric_type:
|
||||
description: metric type of the harvester when reporting
|
||||
type:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ properties:
|
|||
biblio_id:
|
||||
type: integer
|
||||
description: Internal biblio identifier
|
||||
deleted_biblio_id:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
description: Internal deleted biblio identifier
|
||||
item_group_id:
|
||||
type:
|
||||
- string
|
||||
|
|
|
|||
|
|
@ -119,6 +119,11 @@ properties:
|
|||
description: List of aliases
|
||||
items:
|
||||
$ref: "vendor_alias.yaml"
|
||||
subscriptions_count:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
description: Number of linked subscriptions
|
||||
additionalProperties: false
|
||||
required:
|
||||
- name
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
type: string
|
||||
enum:
|
||||
- extended_attributes
|
||||
- library
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@
|
|||
type: string
|
||||
enum:
|
||||
- extended_attributes
|
||||
- library
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
@ -149,6 +150,7 @@
|
|||
type: string
|
||||
enum:
|
||||
- extended_attributes
|
||||
- library
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
type: string
|
||||
enum:
|
||||
- aliases
|
||||
- subscriptions+count
|
||||
collectionFormat: csv
|
||||
responses:
|
||||
"200":
|
||||
|
|
|
|||
|
|
@ -472,6 +472,7 @@
|
|||
- item_type
|
||||
- in_bundle
|
||||
- bundle_host
|
||||
- bundle_host.biblio
|
||||
- bundle_items_lost+count
|
||||
- bundle_items_not_lost+count
|
||||
- course_item.course_reserves.course
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
type: string
|
||||
enum:
|
||||
- extended_attributes
|
||||
- library
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@
|
|||
- cancellation_requested
|
||||
- biblio
|
||||
- pickup_library
|
||||
collectionFormat: csv
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@
|
|||
type: string
|
||||
enum:
|
||||
- extended_attributes
|
||||
- library
|
||||
collectionFormat: csv
|
||||
produces:
|
||||
- application/json
|
||||
|
|
|
|||
|
|
@ -540,7 +540,6 @@ my $error = $input->param('error');
|
|||
my $authid = $input->param('authid') =~ s/\D//gr
|
||||
; # if authid exists, it's a modif, not a new authority. We remove from authid all non-digit characters just in case the CGI parameter contains weird characters like spaces
|
||||
my $op = $input->param('op');
|
||||
my $nonav = $input->param('nonav');
|
||||
my $myindex = $input->param('index');
|
||||
my $linkid=$input->param('linkid');
|
||||
my $authtypecode = $input->param('authtypecode');
|
||||
|
|
@ -570,7 +569,7 @@ my ($template, $loggedinuser, $cookie)
|
|||
type => "intranet",
|
||||
flagsrequired => {editauthorities => 1},
|
||||
});
|
||||
$template->param(nonav => $nonav,index=>$myindex,authtypecode=>$authtypecode,breedingid=>$breedingid, count=>$count);
|
||||
$template->param( index => $myindex, authtypecode => $authtypecode, breedingid => $breedingid, count => $count );
|
||||
|
||||
$tagslib = GetTagsLabels(1,$authtypecode);
|
||||
$mandatory_z3950 = GetMandatoryFieldZ3950($authtypecode);
|
||||
|
|
@ -632,15 +631,6 @@ if ($op eq "cud-add") {
|
|||
duplicateauthvalue => $duplicateauthvalue->{'authorized'}->[0]->{'heading'},
|
||||
);
|
||||
}
|
||||
} elsif ($op eq "cud-delete") {
|
||||
#------------------------------------------------------------------------------------------------------------------------------
|
||||
DelAuthority({ authid => $authid });
|
||||
if ($nonav){
|
||||
print $input->redirect("auth_finder.pl");
|
||||
}else{
|
||||
print $input->redirect("authorities-home.pl?authid=0");
|
||||
}
|
||||
exit;
|
||||
} else {
|
||||
if ( $op eq "duplicate" ) {
|
||||
$authid = "";
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
|
|||
my $op = $query->param("op");
|
||||
my $format = $query->param("format");
|
||||
my $error = '';
|
||||
if ( $op eq "cud-export" ) {
|
||||
if ( $op eq "export" ) {
|
||||
my $authid = $query->param("authid");
|
||||
if ($authid) {
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,6 @@ use C4::Languages qw( getlanguage getLanguages );
|
|||
use C4::Koha qw( getitemtypeimagelocation GetAuthorisedValues );
|
||||
use URI::Escape;
|
||||
use POSIX qw(ceil floor);
|
||||
use C4::Search qw( searchResults enabled_staff_search_views z3950_search_args new_record_from_zebra );
|
||||
|
||||
use Koha::ItemTypes;
|
||||
use Koha::Library::Groups;
|
||||
|
|
@ -243,7 +242,7 @@ my @search_groups =
|
|||
|
||||
my $branch_limit = '';
|
||||
my $limit_param = $cgi->param('limit');
|
||||
if ( $limit_param and $limit_param =~ /branch:([\w-]+)/ ) {
|
||||
if ( $limit_param and $limit_param =~ /^branch:([\w-]+)/ ) {
|
||||
$branch_limit = $1;
|
||||
}
|
||||
|
||||
|
|
@ -425,9 +424,9 @@ if ($params->{'limit-yr'}) {
|
|||
# $ %z3950p will be a hash ref if the indexes are present (advacned search), otherwise undef
|
||||
my $z3950par;
|
||||
my $indexes2z3950 = {
|
||||
kw=>'title', au=>'author', 'au,phr'=>'author', nb=>'isbn', ns=>'issn',
|
||||
'lcn,phr'=>'dewey', su=>'subject', 'su,phr'=>'subject',
|
||||
ti=>'title', 'ti,phr'=>'title', se=>'title'
|
||||
kw => 'title', au => 'author', 'au,phr' => 'author', nb => 'isbn', ns => 'issn',
|
||||
callnum => 'dewey', su => 'subject', 'su,phr' => 'subject',
|
||||
ti => 'title', 'ti,phr' => 'title', se => 'title'
|
||||
};
|
||||
for (my $ii = 0; $ii < @operands; ++$ii)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,12 +50,14 @@ my $builder = sub {
|
|||
function Click$params->{id}(ev) {
|
||||
ev.preventDefault();
|
||||
var code = document.getElementById(ev.data.id);
|
||||
const csrf_token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
\$.ajax({
|
||||
url: '/cgi-bin/koha/cataloguing/plugin_launcher.pl',
|
||||
type: 'POST',
|
||||
data: {
|
||||
'plugin_name': 'stocknumberAV.pl',
|
||||
'code' : code.value,
|
||||
'csrf_token': csrf_token
|
||||
},
|
||||
success: function(data){
|
||||
var field = document.getElementById(ev.data.id);
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ if ( $op eq 'cud-edit_message' && $message_id ) {
|
|||
|
||||
my $url = $input->referer;
|
||||
if ($url) {
|
||||
if ( $url =~ m|circulation\.pl$| ) {
|
||||
if ( $url =~ m/(circulation\.pl|members\/files\.pl)$/ ) {
|
||||
|
||||
# Trick for POST form from batch checkouts
|
||||
$url .= "?borrowernumber=$borrowernumber";
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ $template->param(
|
|||
caller => 'article-request',
|
||||
plain => 0,
|
||||
style => $style,
|
||||
id => 'ar_slip',
|
||||
);
|
||||
|
||||
output_html_with_http_headers $cgi, $cookie, $template->output;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user (
|
|||
}
|
||||
);
|
||||
|
||||
my $op = $query->param('op');
|
||||
my $op = $query->param('op') // '';
|
||||
my $override_high_holds = $query->param('override_high_holds');
|
||||
my $override_high_holds_tmp = $query->param('override_high_holds_tmp');
|
||||
|
||||
|
|
@ -364,19 +364,16 @@ if (@$barcodes && $op eq 'cud-checkout') {
|
|||
}
|
||||
|
||||
if ( $issuingimpossible->{'STATS'} ) {
|
||||
$template->param( STATS => 1 );
|
||||
my ( $stats_return, $stats_messages, $stats_iteminformation, $stats_borrower ) =
|
||||
AddReturn( $item->barcode, C4::Context->userenv->{'branch'}, undef, undef, 1 );
|
||||
|
||||
if ( $item->onloan ) {
|
||||
my ( $stats_return, $stats_messages, $stats_iteminformation, $stats_borrower ) =
|
||||
AddReturn( $item->barcode, C4::Context->userenv->{'branch'}, undef, undef, 1 );
|
||||
|
||||
$template->param(
|
||||
CHECKEDIN => $stats_return,
|
||||
MESSAGES => $stats_messages,
|
||||
ITEM => $stats_iteminformation,
|
||||
BORROWER => $stats_borrower,
|
||||
);
|
||||
}
|
||||
$template->param(
|
||||
STATS => 1,
|
||||
CHECKEDIN => $stats_return,
|
||||
MESSAGES => $stats_messages,
|
||||
ITEM => $stats_iteminformation,
|
||||
BORROWER => $stats_borrower,
|
||||
);
|
||||
|
||||
#increment items.localuse
|
||||
my $localuse_count = $item->localuse;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ $template->param( slip => $slip ) if ($slip);
|
|||
$template->param( caller => 'hold-transfer' );
|
||||
$template->param( plain => !$is_html );
|
||||
$template->param( style => $style );
|
||||
$template->param( id => 'reserve_slip' );
|
||||
|
||||
output_html_with_http_headers $input, $cookie, $template->output;
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ if ( $holds->count ) {
|
|||
# patrons count per biblio
|
||||
my $patrons_count = {
|
||||
map { $_->{biblionumber} => $_->{patrons_count} } @{ Koha::Holds->search(
|
||||
{ 'suspend' => 0 },
|
||||
{ 'suspend' => 0, 'found' => undef },
|
||||
{
|
||||
select => [ 'biblionumber', { count => { distinct => 'borrowernumber' } } ],
|
||||
as => [qw( biblionumber patrons_count )],
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ foreach ( $query->param ) {
|
|||
push( @inputloop, \%input );
|
||||
}
|
||||
|
||||
my $op = $query->param('op');
|
||||
my $op = $query->param('op') // '';
|
||||
|
||||
############
|
||||
# Deal with the requests....
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ $template->param(
|
|||
caller => 'cud-transfer',
|
||||
stylesheet => C4::Context->preference("SlipCSS"),
|
||||
style => $style,
|
||||
id => 'transfer_slip',
|
||||
);
|
||||
|
||||
output_html_with_http_headers $input, $cookie, $template->output;
|
||||
|
|
|
|||
|
|
@ -145,23 +145,24 @@ if ($item && $tab eq 'holdsover' && !@cancel_result) {
|
|||
exit;
|
||||
|
||||
sub cancel {
|
||||
my ($item, $borrowernumber, $fbr, $tbr, $skip_transfers ) = @_;
|
||||
my ( $itemnumber, $borrowernumber, $fbr, $tbr, $skip_transfers ) = @_;
|
||||
|
||||
my $transfer = $fbr ne $tbr; # XXX && !$nextreservinfo;
|
||||
my $item = Koha::Items->find( $itemnumber );
|
||||
|
||||
return if $transfer && $skip_transfers;
|
||||
|
||||
my ( $messages, $nextreservinfo ) = ModReserveCancelAll( $item, $borrowernumber );
|
||||
my ( $messages, $nextreservinfo ) = ModReserveCancelAll( $itemnumber, $borrowernumber );
|
||||
|
||||
# if the document is not in his homebranch location and there is not reservation after, we transfer it
|
||||
if ($transfer && !$nextreservinfo) {
|
||||
ModItemTransfer( $item, $fbr, $tbr, 'CancelReserve' );
|
||||
if ( $transfer && !$nextreservinfo && !$item->itemlost ) {
|
||||
ModItemTransfer( $itemnumber, $fbr, $tbr, 'CancelReserve' );
|
||||
}
|
||||
# if we have a result
|
||||
if ($nextreservinfo) {
|
||||
my %res;
|
||||
my $patron = Koha::Patrons->find( $nextreservinfo );
|
||||
my $title = Koha::Items->find( $item )->biblio->title;
|
||||
my $title = $item->biblio->title;
|
||||
if ( $messages->{'transfert'} ) {
|
||||
$res{messagetransfert} = $messages->{'transfert'};
|
||||
$res{branchcode} = $messages->{'transfert'};
|
||||
|
|
@ -171,7 +172,7 @@ sub cancel {
|
|||
$res{nextreservnumber} = $nextreservinfo;
|
||||
$res{nextreservsurname} = $patron->surname;
|
||||
$res{nextreservfirstname} = $patron->firstname;
|
||||
$res{nextreservitem} = $item;
|
||||
$res{nextreservitem} = $itemnumber;
|
||||
$res{nextreservtitle} = $title;
|
||||
$res{waiting} = $messages->{'waiting'} ? 1 : 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@
|
|||
<term><option>--queue</option></term>
|
||||
<listitem>
|
||||
<para>Allows specifying the queue worker (defaults to 'default').</para>
|
||||
<para>Current queues are: default, long_tasks, elastic_index.</para>
|
||||
<para>Current queues are: default, long_tasks.</para>
|
||||
<para>Note: There used to be a queue called elastic_index, but since the introduction of koha-es-indexer this queue should not be active.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ $scriptname [--quiet|-q] [--exclude-indexes] instancename1 [instancename2...]
|
|||
$scriptname -h|--help
|
||||
|
||||
--schema-only Dump only the database schema
|
||||
--exclude-indexes Include Zebra indexes on the backup
|
||||
--exclude-indexes Exclude Zebra indexes from the backup
|
||||
--exclude-logs Exclude /var/log/koha/name from the backup
|
||||
--uploaded_files Include uploaded files.
|
||||
--uploaded_temp_files Include temporary uploaded files.
|
||||
|
|
@ -124,30 +124,37 @@ dump_instance()
|
|||
output="$output to $metadump"
|
||||
[ "$quiet" = "no" ] && echo "$output"
|
||||
|
||||
# tar has exit status 1 if any file has changed while being read,
|
||||
# which is likely to happen as the logfiles are included.
|
||||
set +e
|
||||
|
||||
if [ "$exclude_logs" = "yes" ]; then
|
||||
tar -czf "$metadump" -C / $excludes \
|
||||
"etc/koha/sites/$name" \
|
||||
"etc/apache2/sites-available/$instancefile" \
|
||||
"etc/apache2/sites-enabled/$instancefile" \
|
||||
"var/lib/koha/$name" \
|
||||
$uploaded_files_dir \
|
||||
$uploaded_temp_files_dir
|
||||
|
||||
chown "root:$name-koha" "$metadump"
|
||||
chmod g+r "$metadump"
|
||||
tar -czf "$metadump" -C / $excludes \
|
||||
"etc/koha/sites/$name" \
|
||||
"etc/apache2/sites-available/$instancefile" \
|
||||
"etc/apache2/sites-enabled/$instancefile" \
|
||||
"var/lib/koha/$name" \
|
||||
$uploaded_files_dir \
|
||||
$uploaded_temp_files_dir
|
||||
else
|
||||
tar -czf "$metadump" -C / $excludes \
|
||||
"etc/koha/sites/$name" \
|
||||
"etc/apache2/sites-available/$instancefile" \
|
||||
"etc/apache2/sites-enabled/$instancefile" \
|
||||
"var/lib/koha/$name" \
|
||||
"var/log/koha/$name" \
|
||||
$uploaded_files_dir \
|
||||
$uploaded_temp_files_dir
|
||||
tar -czf "$metadump" -C / $excludes \
|
||||
"etc/koha/sites/$name" \
|
||||
"etc/apache2/sites-available/$instancefile" \
|
||||
"etc/apache2/sites-enabled/$instancefile" \
|
||||
"var/lib/koha/$name" \
|
||||
"var/log/koha/$name" \
|
||||
$uploaded_files_dir \
|
||||
$uploaded_temp_files_dir
|
||||
fi
|
||||
|
||||
if [ "$?" != "1" -a "$?" != "0" ]; then
|
||||
exit $?
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
chown "root:$name-koha" "$metadump"
|
||||
chmod g+r "$metadump"
|
||||
fi
|
||||
|
||||
[ "$quiet" = "no" ] && echo "Done."
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -90,12 +90,12 @@ run_rebuild_elasticsearch()
|
|||
KOHA_BINDIR=${KOHA_HOME}/misc
|
||||
fi
|
||||
|
||||
if [ "${clo_commit_size}" > 0 ]; then
|
||||
if [ "${clo_commit_size}" -gt 0 ] 2>/dev/null; then
|
||||
commit_size=${clo_commit_size}
|
||||
fi
|
||||
rebuild_opts="--commit ${commit_size}"
|
||||
|
||||
if [ "${clo_processes}" > 0 ]; then
|
||||
if [ "${clo_processes}" -gt 0 ] 2>/dev/null; then
|
||||
processes=${clo_processes}
|
||||
fi
|
||||
rebuild_opts="${rebuild_opts} --processes ${processes}"
|
||||
|
|
|
|||
|
|
@ -280,21 +280,21 @@ email turned on.
|
|||
|
||||
Usage: $scriptname [--enabled|--disabled] [--email|--noemail] [--sip|--nosip] [-h]
|
||||
Options:
|
||||
--enabled Show enabled instances
|
||||
--disabled Show disabled instances
|
||||
--elasticsearch Show instances with Elasticsearch enabled
|
||||
--noelasticsarch Show instances with Elasticsearch disabled
|
||||
--email Show instances with email enabled
|
||||
--noemail Show instances with email disabled
|
||||
--sip Show instances with SIP enabled
|
||||
--nosip Show instances with SIP disabled
|
||||
--plack Show instances with Plack enabled
|
||||
--noplack Show instances with Plack disabled
|
||||
--letsencrypt Show instances with letsencrypt enabled
|
||||
--noletsencrypt Show instances with letsencrypt disabled
|
||||
--z3950 Show instances with Z39.50/SRU enabled
|
||||
--noz3950 Show instances with Z39.50/SRU disabled
|
||||
--help | -h Show this help
|
||||
--enabled Show enabled instances
|
||||
--disabled Show disabled instances
|
||||
--elasticsearch Show instances with Elasticsearch enabled
|
||||
--noelasticsearch Show instances with Elasticsearch disabled
|
||||
--email Show instances with email enabled
|
||||
--noemail Show instances with email disabled
|
||||
--sip Show instances with SIP enabled
|
||||
--nosip Show instances with SIP disabled
|
||||
--plack Show instances with Plack enabled
|
||||
--noplack Show instances with Plack disabled
|
||||
--letsencrypt Show instances with letsencrypt enabled
|
||||
--noletsencrypt Show instances with letsencrypt disabled
|
||||
--z3950 Show instances with Z39.50/SRU enabled
|
||||
--noz3950 Show instances with Z39.50/SRU disabled
|
||||
--help | -h Show this help
|
||||
|
||||
The filtering options can be combined, and you probably want to do this
|
||||
(except --email and --noemail, or --enabled and --disabled, that's just silly.)
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ if ! test $days -gt 0 ; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
for name in $(koha-list --enabled | grep -Fxv demo)
|
||||
for name in $(koha-list --enabled)
|
||||
do
|
||||
if koha-dump ${exclude_indexes} ${exclude_logs} "$name" > /dev/null; then
|
||||
# Only delete old backups if dump script return success.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue