Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 578 lines (518 sloc) 22.556 kb
#!/usr/bin/env perl
# Copyright 2000-2002 Katipo Communications
#
# 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
use CGI;
use strict;
use warnings;
use C4::Auth;
use C4::Output;
use C4::Biblio;
use C4::Items;
use Koha;
use C4::Context;
use C4::Dates;
use C4::Form::AddItem;
use C4::Branch;
use C4::Koha;
use C4::ClassSource;
use C4::Reserves;
use C4::Session::Defaults::Items;
use MARC::File::XML;
my $input = new CGI;
my $dbh = C4::Context->dbh;
my $error = $input->param('error');
my $biblionumber = $input->param('biblionumber');
my $itemnumber = $input->param('itemnumber') || '';
my $op = $input->param('op') || '';
$op = 'set_session_defaults' if ( $input->param('set_session_defaults') );
$op = 'clear_session_defaults' if ( $input->param('clear_session_defaults') );
$op = 'load_session_defaults' if ( $input->param('load_session_defaults') );
$op = 'delete_session_defaults' if ( $input->param('delete_session_defaults') );
my ($template, $loggedinuser, $cookie)
= get_template_and_user({template_name => "cataloguing/additem.tmpl",
query => $input,
type => "intranet",
authnotrequired => 0,
flagsrequired => {editcatalogue => '*'},
debug => 1,
});
## $restrict is for the concept of Work Libraries, wherein logged in
## librarian can only add/edit/delete/move items in their own work library(ies).
## sorry, I don't know how to get to the template params by method -hQ
my $restrict = C4::Context->preference('EditAllLibraries') ?undef:1;
$restrict = undef if $$template{param_map}{CAN_user_superlibrarian};
my $frameworkcode = &GetFrameworkCode($biblionumber);
my $today_iso = C4::Dates->today('iso');
$template->param(today_iso => $today_iso);
my $bctype = C4::Context->preference('autoBarcode') // '';
$bctype = '' if lc($bctype) eq 'off';
my $tagslib = &GetMarcStructure(1,$frameworkcode);
my $record = GetMarcBiblio($biblionumber);
my $oldrecord = TransformMarcToKoha($dbh,$record);
my $itemrecord;
my @omissions=();
my @today_fields=();
my $nextop="additem";
my @errors; # store errors found while checking data BEFORE saving item.
#-------------------------------------------------------------------------------
if ($op eq 'set_session_defaults') {
#-------------------------------------------------------------------------------
my @tags = $input->param( 'tag_0' );
my @subfields = $input->param( 'subfield_0' );
my @values = $input->param( 'field_value_0' );
my $item_defaults = new C4::Session::Defaults::Items();
for( my $i = 0; $i < @values; $i++ ) {
$item_defaults->set( field => $tags[$i], subfield => $subfields[$i], value => $values[$i] );
}
my $session_defaults_name = $input->param( 'session_defaults_name' );
$item_defaults->save( name => $session_defaults_name ) if ( $session_defaults_name );
#-------------------------------------------------------------------------------
} elsif ($op eq 'clear_session_defaults') {
#-------------------------------------------------------------------------------
my $item_defaults = new C4::Session::Defaults::Items();
$item_defaults->clear();
#-------------------------------------------------------------------------------
} elsif ($op eq 'load_session_defaults') {
#-------------------------------------------------------------------------------
my $item_defaults = new C4::Session::Defaults::Items();
my $session_defaults_to_load = $input->param( 'session_defaults_to_load' );
$item_defaults->load( name => $session_defaults_to_load );
#-------------------------------------------------------------------------------
} elsif ($op eq 'delete_session_defaults') {
#-------------------------------------------------------------------------------
my $item_defaults = new C4::Session::Defaults::Items();
$item_defaults->delete();
#-------------------------------------------------------------------------------
} elsif ($op eq "additem") {
#-------------------------------------------------------------------------------
my ( $record, $barcode_not_unique ) = C4::Form::AddItem::get_item_record( $input, $frameworkcode, 0 );
# type of add
my $add_submit = $input->param('add_submit');
my $add_duplicate_submit = $input->param('add_duplicate_submit');
my $add_multiple_copies_submit = $input->param('add_multiple_copies_submit');
my $number_of_copies = $input->param('number_of_copies');
my $addedolditem = TransformMarcToKoha($dbh,$record);
# If we have to add or add & duplicate, we add the item
if ($add_submit || $add_duplicate_submit) {
# note: if barcode validation is performed, this is already done/passed -hQ
# check for item barcode # being unique
my $exist_itemnumber = get_item_from_barcode($addedolditem->{'barcode'});
push @errors,"barcode_not_unique" if($exist_itemnumber);
# if barcode exists, don't create, but report The problem.
unless ($exist_itemnumber) {
my ($oldbiblionumber,$oldbibnum,$oldbibitemnum) = AddItemFromMarc($record,$biblionumber);
set_item_default_location($oldbibitemnum);
}
$nextop = "additem";
if ($exist_itemnumber) {
$itemrecord = $record;
}
}
# If we have to add & duplicate
if ($add_duplicate_submit) {
my ($tagfield,$tagsubfield) = &GetMarcFromKohaField("items.barcode",$frameworkcode);
if ($bctype) {
# We try to get the next barcode
use C4::Barcodes;
my $barcodeobj = C4::Barcodes->new;
my $barcodevalue = $barcodeobj->next_value($addedolditem->{'barcode'}) if $barcodeobj;
if ($record->field($tagfield)->subfield($tagsubfield)) {
# If we got the next codebar value, we put it in the record
if ($barcodevalue) {
$record->field($tagfield)->update($tagsubfield => $barcodevalue);
# If not, we delete the recently inserted barcode from the record (so the user can input a barcode himself)
} else {
$record->field($tagfield)->update($tagsubfield => '');
}
}
}
else {
$record->field($tagfield)->update($tagsubfield => '');
}
$itemrecord = $record;
}
# If we have to add multiple copies
if ($add_multiple_copies_submit) {
use C4::Barcodes;
my $barcodeobj = C4::Barcodes->new;
my $oldbarcode = $addedolditem->{'barcode'};
my ($tagfield,$tagsubfield) = &GetMarcFromKohaField("items.barcode",$frameworkcode);
# If there is a barcode and we can't find him new values, we can't add multiple copies
my $testbarcode = $barcodeobj->next_value($oldbarcode) if $barcodeobj;
if ($oldbarcode && !$testbarcode) {
push @errors, "no_next_barcode";
$itemrecord = $record;
} else {
# We add each item
# For the first iteration
my $barcodevalue = $oldbarcode;
my $exist_itemnumber;
for (my $i = 0; $i < $number_of_copies;) {
# If there is a barcode
if ($barcodevalue) {
# Getting a new barcode (if it is not the first iteration or the barcode we tried already exists)
$barcodevalue = $barcodeobj->next_value($oldbarcode) if ($i > 0 || $exist_itemnumber);
# Putting it into the record
if ($barcodevalue) {
$record->field($tagfield)->update($tagsubfield => $barcodevalue);
}
# Checking if the barcode already exists
$exist_itemnumber = C4::Form::AddItem::get_item_from_barcode($barcodevalue);
}
# Adding the item
if (!$exist_itemnumber) {
my ($oldbiblionumber,$oldbibnum,$oldbibitemnum) = AddItemFromMarc($record,$biblionumber);
set_item_default_location($oldbibitemnum);
# We count the item only if it was really added
# That way, all items are added, even if there was some already existing barcodes
# FIXME : Please note that there is a risk of infinite loop here if we never find a suitable barcode
$i++;
}
# Preparing the next iteration
$oldbarcode = $barcodevalue;
}
undef($itemrecord);
}
}
#-------------------------------------------------------------------------------
} elsif ($op eq "edititem") {
#-------------------------------------------------------------------------------
# retrieve item if exist => then, it's a modif
$template->param('mv' => 1);
$itemrecord = C4::Items::GetMarcItem($biblionumber,$itemnumber);
$nextop = "saveitem";
#-------------------------------------------------------------------------------
} elsif ($op eq "addadditionalitem") {
#-------------------------------------------------------------------------------
# retrieve marc_value field of an existing record
$itemrecord = C4::Items::GetMarcItem($biblionumber,$itemnumber);
@omissions=('items.barcode','items.itemlost','items.damaged','items.wthdrawn','items.datelastborrowed',
'items.notforloan','items.issues','items.renewals','items.reserves','items.restricted','items.onloan',
'items.materials','items.copynumber');
@today_fields=('items.datelastseen','items.dateaccessioned');
$nextop="additem";
#-------------------------------------------------------------------------------
} elsif ($op eq "delitem") {
#-------------------------------------------------------------------------------
my $delete_holds_permission = $template->param('CAN_user_reserveforothers_delete_holds');
## check whether this is the last item in the bib record,
## if so, we can't delete it if there are holds on the bib.
my $forceDelLastItem = $input->param('forceDelLastItem');
my $continue = 1;
if (C4::Items::isLastItemInBib($biblionumber,$itemnumber) && !$forceDelLastItem) {
if (@{C4::Reserves::GetReservesFromBiblionumber($biblionumber) // []}) {
push @errors, 'title_has_holds';
$continue = 0;
}
}
if ($continue) {
# check that there is no issue on this item before deletion.
my $sth=$dbh->prepare("select * from issues i where i.itemnumber=?");
$sth->execute($itemnumber);
my $onloan=$sth->fetchrow_hashref;
$sth->finish();
$nextop="additem";
if ($onloan){
push @errors,"book_on_loan";
} elsif ( GetReservesFromItemnumber( $itemnumber ) && !$delete_holds_permission ) {
push @errors,"item_has_holds";
} else {
# check it doesnt have a waiting reserve
$sth=$dbh->prepare("SELECT * FROM reserves WHERE found = 'W' AND itemnumber = ?");
$sth->execute($itemnumber);
my $reserve=$sth->fetchrow_hashref;
if ($reserve) {
push @errors, "item_waiting";
} else {
if ($forceDelLastItem) {
if ($input->param('also_delete_holds')) {
CancelReserves({biblionumber=>$biblionumber});
}
else {
## bib-level holds will magically reappear when an item is added
## for this bib. delete only item-level holds
CancelReserves({biblionumber=>$biblionumber,itemnumber=>$itemnumber});
}
}
else {
CancelReserves({ itemnumber => $itemnumber });
}
&DelItem($dbh,$biblionumber,$itemnumber);
print $input->redirect("additem.pl?biblionumber=$biblionumber&frameworkcode=$frameworkcode");
exit;
}
push @errors,"book_reserved";
}
}
#-------------------------------------------------------------------------------
} elsif ($op eq "saveitem") {
#-------------------------------------------------------------------------------
MoveItemToAnotherBiblio( $itemnumber, $biblionumber );
if ($input->param('mv')) {
C4::Reserves::fixPrioritiesOnItemMove($biblionumber);
}
if ($input->param('nukeHolds')) {
my %p = ('itemnumber',$itemnumber);
if ($input->param('onlyiteminbib')) {
$p{biblionumber} = $biblionumber;
delete($p{itemnumber});
}
C4::Reserves::CancelReserves(\%p);
}
# rebuild
my ( $itemtosave, $barcode_not_unique ) = C4::Form::AddItem::get_item_record( $input, $frameworkcode, 0, $itemnumber );
if ( $barcode_not_unique ) {
push @errors, 'barcode_not_unique';
} else {
my ($oldbiblionumber,$oldbibnum,$oldbibitemnum) = ModItemFromMarc($itemtosave,$biblionumber,$itemnumber);
$itemnumber="";
}
$nextop="additem";
}
## Check to see if we are working on a new item for the record
$template->param( newitem => 1 ) if ( $op eq '' || $op eq "addadditionalitem" );
#
#-------------------------------------------------------------------------------
# build screen with existing items. and "new" one
#-------------------------------------------------------------------------------
# now, build existiing item list
my $temp = GetMarcWithItems( $biblionumber );
my @fields = $temp->fields();
#my @fields = $record->fields();
my %witness; #---- stores the list of subfields used at least once, with the "meaning" of the code
my @big_array;
#---- finds where items.itemnumber is stored
my ( $itemtagfield, $itemtagsubfield) = &GetMarcFromKohaField("items.itemnumber", $frameworkcode);
my ($branchtagfield, $branchtagsubfield) = &GetMarcFromKohaField("items.homebranch", $frameworkcode);
foreach my $field (@fields) {
next if ($field->tag()<10);
my @subf = $field->subfields or (); # don't use ||, as that forces $field->subfelds to be interpreted in scalar context
my %this_row;
# loop through each subfield
for my $i (0..$#subf) {
## Suppress Perl warnings about uninitialized values.
next unless defined $field->tag();
next unless defined $tagslib->{$field->tag()};
next unless defined $subf[$i][0];
next unless defined $tagslib->{$field->tag()}->{$subf[$i][0]};
$tagslib->{$field->tag()}->{$subf[$i][0]}->{tab} //= undef;
next if ($tagslib->{$field->tag()}->{$subf[$i][0]}->{tab} ne 10
&& ($field->tag() ne $itemtagfield
&& $subf[$i][0] ne $itemtagsubfield));
$witness{$subf[$i][0]} = $tagslib->{$field->tag()}->{$subf[$i][0]}->{lib} if ($tagslib->{$field->tag()}->{$subf[$i][0]}->{tab} eq 10);
$tagslib->{$field->tag()} //= undef;
if ($tagslib->{$field->tag()}->{$subf[$i][0]}->{tab} eq 10) {
$this_row{$subf[$i][0]}=GetAuthorisedValueDesc( $field->tag(),
$subf[$i][0], $subf[$i][1], '', $tagslib)
|| $subf[$i][1];
}
if (($field->tag eq $branchtagfield) && ($subf[$i][0] eq $branchtagsubfield) && C4::Context->preference("IndependantBranches")) {
#verifying rights
my $userenv = C4::Context->userenv();
unless (($userenv->{'flags'} == 1) or (($userenv->{'branch'} eq $subf[$i][1]))){
$this_row{'nomod'}=1;
}
}
$this_row{itemnumber} = $subf[$i][1] if ($field->tag() eq $itemtagfield && $subf[$i][0] eq $itemtagsubfield);
}
if (%this_row) {
push(@big_array, \%this_row);
}
}
#use Data::Dumper;
#warn Dumper \%witness;
my ($holdingbrtagf,$holdingbrtagsubf) = &GetMarcFromKohaField("items.holdingbranch",$frameworkcode);
@big_array = sort {$a->{$holdingbrtagsubf} cmp $b->{$holdingbrtagsubf}} @big_array;
# determing working library(ies) edit/delete for EditAllLibraries=0
my @worklibs;
if ($restrict) {
my $usrCurrLib = C4::Context->userenv->{'branch'};
$usrCurrLib = '' if $usrCurrLib eq 'NO_LIBRARY_SET';
unless ($usrCurrLib) {
# need to set the current library
# warp speed out of here and come back later
print $input->redirect('/cgi-bin/koha/circ/selectbranchprinter.pl');
exit;
}
my $borrowernumber = C4::Members::GetBorrowerFromUser(
C4::Context->userenv->{id}
);
@worklibs = C4::Members::GetWorkLibraries($borrowernumber);
}
$template->param(restrict=>$restrict);
# now, construct template !
# First, the existing items for display
my @item_value_loop;
my @header_value_loop;
my $branches = GetBranches;
my %br = (); # reverse branch hash
foreach(keys %$branches) {
$br{$$branches{$_}{branchname}} = $_;
}
for my $row ( @big_array ) {
my %row_data;
my @item_fields = map +{ field => $_ || '' }, @$row{ sort keys(%witness) };
$row_data{item_value} = [ @item_fields ];
$row_data{itemnumber} = $row->{itemnumber};
$row_data{holds} = ( GetReservesFromItemnumber( $row->{itemnumber} ) );
#reporting this_row values
if ($restrict) { # cmp permanent location w/ worklibraries
if ($br{$$row{a}} ~~ @worklibs) {
$$row{nomod} = 0;
}
else {
$$row{nomod} = 1;
}
}
$row_data{'nomod'} = $row->{'nomod'} // 0;
$row_data{a} //= '';
push(@item_value_loop,\%row_data);
}
# re-sort, editable items on top, then by permanent location
@item_value_loop = sort {
$$a{nomod} <=> $$b{nomod}
|| $$a{a} cmp $$b{a}
} @item_value_loop;
foreach my $subfield_code (sort keys(%witness)) {
my %header_value;
$header_value{header_value} = $witness{$subfield_code};
push(@header_value_loop, \%header_value);
}
my $item = C4::Form::AddItem::get_form_values( $tagslib, 0, {
item => $itemrecord,
biblio => $temp,
wipe => \@omissions ,
make_today => \@today_fields,
frameworkcode => $frameworkcode,
worklibs => \@worklibs,
});
if (@worklibs && $itemnumber) { # item ownership
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT homebranch FROM items
WHERE itemnumber = ?");
$sth->execute($itemnumber);
my($homebranch) = ($sth->fetchrow_array)[0];
%br = ();
foreach(@worklibs) { $br{$_} = 1 };
if ($br{$homebranch}) {
# do nothing
}
else {
$template->param('notmyitem'=>1);
}
}
## Move barcode field to the top of the list.
my $barcode_index = 0;
for my $i(0..$#{$item}) {
if (($$item[$i]{tag} ~~ '952') && ($$item[$i]{subfield} ~~ 'p')) {
$barcode_index = $i;
last;
}
}
my @tmp = splice( @$item, $barcode_index, 1 );
my $t = $tmp[0];
my $barcode_id = $t->{id};
unshift( @$item, $t );
## pass DOM id of permanent location 952$a to template so
## that ajax call for barcode validation knows the branchcode.
## also pass for damaged status
my $i = 0;
foreach(@$item) {
if ($$_{tag} eq '952') {
if ($$_{subfield} eq 'a') {
$template->param(branchcode_tag_id => $$_{id});
}
elsif ($$_{subfield} eq '4') {
$template->param(damaged_tag_id => $$_{id});
$template->param(AllowHoldsOnDamagedItems =>
C4::Context->preference('AllowHoldsOnDamagedItems')
);
}
# elsif (($$_{subfield} eq 'p') && !$bctype) {
# $$_{marc_value} =~ s/(value\=\")([^\"]*)(\")/$1$3/s;
# }
}
## reset subfield's marc_lib
$$_{marc_lib} =~ s/^(<span id\=\"error)(\d+)/$1$i/;
$i++;
}
# what's the next op ? it's what we are not in : an add if we're editing, otherwise, and edit.
$template->param( title => $record->title() ) if ($record ne "-1");
$template->param(
barcode_id => $barcode_id,
biblionumber => $biblionumber,
title => $oldrecord->{title},
author => $oldrecord->{author},
item_loop => \@item_value_loop,
item_header_loop => \@header_value_loop,
item => $item,
itemnumber => $itemnumber,
itemtagfield => $itemtagfield,
itemtagsubfield => $itemtagsubfield,
op => $nextop,
opisadd => ($nextop eq "saveitem") ? 0 : 1,
C4::Search::enabled_staff_search_views,
);
foreach my $error (@errors) {
$template->param($error => 1);
}
my $item_defaults = new C4::Session::Defaults::Items();
$template->param(
item_defaults_using => $item_defaults->isUsingDefaults(),
item_defaults_name => $item_defaults->name(),
item_defaults_loop => $item_defaults->getSavedDefaultsList(),
item_defaults_all_loop => $item_defaults->getSavedDefaultsList( getAll => 1 ),
);
$template->param( branchcode => C4::Context->userenv->{"branch"} ) unless ( C4::Context->userenv->{"branch"} eq 'NO_LIBRARY_SET' );
output_html_with_http_headers $input, $cookie, $template->output;
sub find_value {
my ($tagfield,$insubfield,$record) = @_;
my $result;
my $indicator;
foreach my $field ($record->field($tagfield)) {
my @subfields = $field->subfields();
foreach my $subfield (@subfields) {
if (@$subfield[0] eq $insubfield) {
$result .= @$subfield[1];
$indicator = $field->indicator(1).$field->indicator(2);
}
}
}
return($indicator,$result);
}
sub get_item_from_barcode {
my ($barcode)=@_;
my $dbh=C4::Context->dbh;
my $result;
my $rq=$dbh->prepare("SELECT itemnumber from items where items.barcode=?");
$rq->execute($barcode);
($result)=$rq->fetchrow;
return($result);
}
sub set_item_default_location {
my $itemnumber = shift;
my $item = GetItem( $itemnumber );
if ( C4::Context->preference('NewItemsDefaultLocation') ) {
$item->{'permanent_location'} = $item->{'location'};
$item->{'location'} = C4::Context->preference('NewItemsDefaultLocation');
ModItem( $item, undef, $itemnumber);
}
else {
$item->{'permanent_location'} = $item->{'location'} if !defined($item->{'permanent_location'});
ModItem( $item, undef, $itemnumber);
}
}
Jump to Line
Something went wrong with that request. Please try again.