@@ -, +, @@ - Display a unique item block at once - PrepareItemrecordDisplay is now used for cloning block --- acqui/check_uniqueness.pl | 70 +++++ acqui/neworderempty.pl | 13 +- acqui/orderreceive.pl | 12 +- .../intranet-tmpl/prog/en/includes/additem.js.inc | 10 + koha-tmpl/intranet-tmpl/prog/en/js/additem.js | 326 +++++++++++++------ .../prog/en/modules/acqui/neworderempty.tt | 90 ++++--- .../prog/en/modules/acqui/orderreceive.tt | 119 +++++--- .../prog/en/modules/services/itemrecorddisplay.tt | 25 ++ services/itemrecorddisplay.pl | 58 ++++ 9 files changed, 522 insertions(+), 201 deletions(-) create mode 100755 acqui/check_uniqueness.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/additem.js.inc create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/services/itemrecorddisplay.tt create mode 100755 services/itemrecorddisplay.pl --- a/acqui/check_uniqueness.pl +++ a/acqui/check_uniqueness.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl + +# Copyright 2011 BibLibre SARL +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use CGI; +use C4::Context; +use C4::Output; +use C4::Auth; + +my $input = new CGI; +my @field = $input->param('field'); +my @value = $input->param('value'); + +my $dbh = C4::Context->dbh; + +my $r; +my $index = 0; +for my $f ( @field ) { + my $query; + given ( $f ) { + when ( "barcode" ) { + $query = "SELECT barcode FROM items WHERE barcode=?"; + } + when ( "stocknumber" ) { + $query = "SELECT stocknumber FROM items WHERE stocknumber=?"; + } + when ( "copynumber" ) { + $query = "SELECT copynumber FROM items WHERE copynumber=?"; + } + } + + if($query) { + my $sth = $dbh->prepare( $query ); + $sth->execute( $value[$index] ); + my @values = $sth->fetchrow_array; + if ( @values ) { + $r .= "$f:$values[0];"; + } + } + $index++; +} + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { template_name => "acqui/ajax.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + debug => 1, + } +); +$template->param( return => $r ); + +output_html_with_http_headers $input, $cookie, $template->output; --- a/acqui/neworderempty.pl +++ a/acqui/neworderempty.pl @@ -317,17 +317,12 @@ if ($CGIsort2) { } if (C4::Context->preference('AcqCreateItem') eq 'ordering' && !$ordernumber) { - # prepare empty item form - my $cell = PrepareItemrecordDisplay('','','','ACQ'); -# warn "==> ".Data::Dumper::Dumper($cell); - unless ($cell) { - $cell = PrepareItemrecordDisplay('','','',''); + # Check if ACQ framework exists + my $marc = GetMarcStructure(1, 'ACQ'); + unless($marc) { $template->param('NoACQframework' => 1); } - my @itemloop; - push @itemloop,$cell; - - $template->param(items => \@itemloop); + $template->param(AcqCreateItemOrdering => 1); } # Get the item types list, but only if item_level_itype is YES. Otherwise, it will be in the item, no need to display it in the biblio my @itemtypes; --- a/acqui/orderreceive.pl +++ a/acqui/orderreceive.pl @@ -116,16 +116,12 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( # prepare the form for receiving if ( $count == 1 ) { if (C4::Context->preference('AcqCreateItem') eq 'receiving') { - # prepare empty item form - my $cell = PrepareItemrecordDisplay('','','','ACQ'); - unless ($cell) { - $cell = PrepareItemrecordDisplay('','','',''); + # Check if ACQ framework exists + my $marc = GetMarcStructure(1, 'ACQ'); + unless($marc) { $template->param('NoACQframework' => 1); } - my @itemloop; - push @itemloop,$cell; - - $template->param(items => \@itemloop); + $template->param(AcqCreateItemReceiving => 1); } if ( @$results[0]->{'quantityreceived'} == 0 ) { --- a/koha-tmpl/intranet-tmpl/prog/en/includes/additem.js.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/additem.js.inc @@ -0,0 +1,10 @@ + --- a/koha-tmpl/intranet-tmpl/prog/en/js/additem.js +++ a/koha-tmpl/intranet-tmpl/prog/en/js/additem.js @@ -1,110 +1,230 @@ -function deleteItemBlock(index) { - var aDiv = document.getElementById(index); - aDiv.parentNode.removeChild(aDiv); - var quantity = document.getElementById('quantity'); - quantity.setAttribute('value',parseFloat(quantity.getAttribute('value'))-1); +function addItem( node ) { + var index = $(node).parent().attr('id'); + var current_qty = parseInt($("#quantity").val()); + var max_qty; + if($("#quantity_to_receive").length != 0){ + max_qty = parseInt($("#quantity_to_receive").val()); + } else { + max_qty = 99999; + } + if ( $("#items_list table").find('tr[idblock="' + index + '"]').length == 0 ) { + if ( current_qty < max_qty ) { + if ( current_qty < max_qty - 1 ) + cloneItemBlock(index); + addItemInList(index); + $("#quantity").val(current_qty + 1); + } else if ( current_qty >= max_qty ) { + alert(window.MSG_ADDITEM_JS_CANT_RECEIVE_MORE_ITEMS + || "You can't receive any more items."); + } + } else { + if ( current_qty < max_qty ) + cloneItemBlock(index); + var tr = constructTrNode(index); + $("#items_list table").find('tr[idblock="' + index + '"]:first').replaceWith(tr); + } + $("#" + index).hide(); +} + +function showItem(index) { + $("#outeritemblock").children("div").each(function(){ + if ( $(this).attr('id') == index ) { + $(this).show(); + } else { + if ( $("#items_list table").find('tr[idblock="' + $(this).attr('id') + '"]').length == 0 ) { + $(this).remove(); + } else { + $(this).hide(); + } + } + }); +} + +function constructTrNode(index) { + var barcode = $('#' + index).find("[name='kohafield'][value='items.barcode']").prevAll("[name='field_value']")[0]; + barcode = $(barcode).val(); + var homebranch = $("#" + index).find("[name='kohafield'][value='items.homebranch']").prevAll("[name='field_value']")[0]; + homebranch = $(homebranch).val(); + var loc = $("#" + index).find("[name='kohafield'][value='items.location']").prevAll("[name='field_value']")[0]; + loc = $(loc).val(); + var callnumber = $("#" + index).find("[name='kohafield'][value='items.itemcallnumber']").prevAll("[name='field_value']")[0]; + callnumber = $(callnumber).val(); + var show_link = "" + + (window.MSG_ADDITEM_JS_SHOW || "Show") + ""; + var del_link = "" + + (window.MSG_ADDITEM_JS_DELETE || "Delete") + ""; + var result = ""; + result += "" + barcode + ""; + result += "" + homebranch + ""; + result += "" + loc + ""; + result += "" + callnumber + ""; + result += "" + show_link + ""; + result += "" + del_link + ""; + result += ""; + + return result; } -function cloneItemBlock(index) { - var original = document.getElementById(index); //original
- var clone = clone_with_selected(original) + +function addItemInList(index) { + $("#items_list").show(); + var tr = constructTrNode(index); + $("#items_list table tbody").append(tr); +} + +function deleteItemBlock(node_a, index) { + $("#" + index).remove(); + var current_qty = parseInt($("#quantity").val()); + var max_qty; + if($("#quantity_to_receive").length != 0) { + max_qty = parseInt($("#quantity_to_receive").val()); + } else { + max_qty = 99999; + } + $("#quantity").val(current_qty - 1); + $(node_a).parents('tr').remove(); + if(current_qty - 1 == 0) + $("#items_list").hide(); + + if ( $("#quantity").val() <= max_qty - 1) { + if ( $("#outeritemblock").children("div :visible").length == 0 ) { + $("#outeritemblock").children("div:last").show(); + } + } + if ( $("#quantity").val() == 0 && $("#outeritemblock > div").length == 0) { + cloneItemBlock(); + } +} + +function cloneItemBlock(index) { + var original; + if(index) { + original = $("#" + index); //original
+ } + var dont_copy_fields = ['items.barcode']; + var random = Math.floor(Math.random()*100000); // get a random itemid. - // set the attribute for the new 'div' subfields - clone.setAttribute('id',index + random);//set another id. - var NumTabIndex; - NumTabIndex = parseInt(original.getAttribute('tabindex')); - if(isNaN(NumTabIndex)) NumTabIndex = 0; - clone.setAttribute('tabindex',NumTabIndex+1); - var CloneButtonPlus; - var CloneButtonMinus; - // try{ - var jclone = $(clone); - CloneButtonPlus = $("a.addItem", jclone).get(0); - CloneButtonPlus.setAttribute('onclick',"cloneItemBlock('" + index + random + "')"); - CloneButtonMinus = $("a.delItem", jclone).get(0); - CloneButtonMinus.setAttribute('onclick',"deleteItemBlock('" + index + random + "')"); - CloneButtonMinus.setAttribute('style',"display:inline"); - // change itemids of the clone - var elems = clone.getElementsByTagName('input'); - for( i = 0 ; elems[i] ; i++ ) - { - if(elems[i].name.match(/^itemid/)) { - elems[i].value = random; + var clone = $("
") + $.ajax({ + url: "/cgi-bin/koha/services/itemrecorddisplay.pl", + dataType: 'html', + data: { + frameworkcode: 'ACQ' + }, + success: function(data, textStatus, jqXHR) { + /* Create the item block */ + $(clone).append(data); + /* Change all itemid fields value */ + $(clone).find("input[name='itemid']").each(function(){ + $(this).val(random); + }); + /* Add buttons + and Clear */ + var buttonPlus = '+'; + var buttonClear = '' + (window.MSG_ADDITEM_JS_CLEAR || 'Clear') + ''; + $(clone).append(buttonPlus).append(buttonClear); + /* Copy values from the original block (input) */ + $(original).find("input[name='field_value']").each(function(){ + var kohafield = $(this).siblings("input[name='kohafield']").val(); + if($(this).val() && dont_copy_fields.indexOf(kohafield) == -1) { + $(this).parent("div").attr("id").match(/^(subfield.)/); + var id = RegExp.$1; + var value = $(this).val(); + $(clone).find("div[id^='"+id+"'] input[name='field_value']").val(value); + } + }); + /* Copy values from the original block (select) */ + $(original).find("select[name='field_value']").each(function(){ + var kohafield = $(this).siblings("input[name='kohafield']").val(); + if($(this).val() && dont_copy_fields.indexOf(kohafield) == -1) { + $(this).parent("div").attr("id").match(/^(subfield.)/); + var id = RegExp.$1; + var value = $(this).val(); + $(clone).find("div[id^='"+id+"'] select[name='field_value']").val(value); + } + }); + + $("#outeritemblock").append(clone); } - } - // } - //catch(e){ // do nothig if ButtonPlus & CloneButtonPlus don't exist. - //} - // insert this line on the page - original.parentNode.insertBefore(clone,original.nextSibling); - var quantity = document.getElementById('quantity'); - quantity.setAttribute('value',parseFloat(quantity.getAttribute('value'))+1); + }); +} + +function clearItemBlock(node) { + var index = $(node).parent().attr('id'); + var block = $("#"+index); + $(block).find("input[type='text']").each(function(){ + $(this).val(""); + }); + $(block).find("select").each(function(){ + $(this).find("option:first").attr("selected", true); + }); } + function check_additem() { - var barcodes = document.getElementsByName('barcode'); - var success = true; - for(i=0;i j) && (barcodes[i].value == barcodes[j].value) && barcodes[i].value !='') { - barcodes[i].className='error'; - barcodes[j].className='error'; - success = false; - } - } - } - // TODO : Add AJAX function to test against barcodes already in the database, not just - // duplicates within the form. - return success; + var success = true; + var array_fields = ['items.barcode']; + var url = '../acqui/check_uniqueness.pl?'; // Url for ajax call + $(".error").empty(); // Clear error div + + // Check if a value is duplicated in form + for ( field in array_fields ) { + var fieldname = array_fields[field].split('.')[1]; + var values = new Array(); + $("[name='kohafield'][value="+array_fields[field]+"]").each(function(){ + var input = $(this).prevAll("input[name='field_value']")[0]; + if($(input).val()) { + values.push($(input).val()); + url += "field=" + fieldname + "&value=" + $(input).val() + "&"; // construct url + } + }); + + var sorted_arr = values.sort(); + for (var i = 0; i < sorted_arr.length - 1; i += 1) { + if (sorted_arr[i + 1] == sorted_arr[i]) { + $(".error").append( + fieldname + " '" + sorted_arr[i] + "' " + + (window.MSG_ADDITEM_JS_IS_DUPLICATE || "is duplicated") + + "
"); + success = false; + } + } + } + + // If there is a duplication, we raise an error + if ( success == false ) { + $(".error").show(); + return false; + } + + // Else, we check in DB + var xmlhttp = null; + xmlhttp = new XMLHttpRequest(); + if ( typeof xmlhttp.overrideMimeType != 'undefined') { + xmlhttp.overrideMimeType('text/xml'); + } + + xmlhttp.open('GET', url, false); + xmlhttp.send(null); + + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {} else {} + }; + var response = xmlhttp.responseText; + var elts = response.split(';'); + if ( response.length > 0 && elts.length > 0 ) { + for ( var i = 0 ; i < elts.length - 1 ; i += 1 ) { + var fieldname = elts[i].split(':')[0]; + var value = elts[i].split(':')[1]; + $(".error").append( + fieldname + " '" + value + "' " + + window.MSG_ADDITEM_JS_ALREADY_EXISTS_IN_DB || "already exists in database" + + "
" + ); + } + success = false; + } + + if ( success == false ) { + $(".error").show(); + } + return success; } -function clone_with_selected (node) { - var origin = node.getElementsByTagName("select"); - var tmp = node.cloneNode(true) - var selectelem = tmp.getElementsByTagName("select"); - for (var i=0; i +[% INCLUDE 'additem.js.inc' %] + [% INCLUDE 'header.inc' %] @@ -18,10 +52,11 @@

Receive items from : [% name %] [% IF ( invoice ) %][[% invoice %]] [% END %] (order #[% ordernumber %])

[% IF ( count ) %] -
+
- + +
Catalog Details
  1. Title: [% title |html %]
  2. @@ -35,48 +70,37 @@ [% seriestitle %]
- [% IF ( items ) %] -
- Item - [% IF ( NoACQframework ) %] -

No ACQ framework, using default. You should create a framework with code ACQ, the items framework would be used

- [% END %] + [% IF (AcqCreateItemReceiving) %] + - [% FOREACH item IN items %] -
-
-
    [% FOREACH iteminformatio IN item.iteminformation %]
  1. -
    - - - [% iteminformatio.marc_value %] - - - - - - [% IF ( iteminformatio.ITEM_SUBFIELDS_ARE_NOT_REPEATABLE ) %] - + - [% END %] - -
  2. +
    + Item + [% IF ( NoACQframework ) %] +

    + No ACQ framework, using default. You should create a + framework with code ACQ, the items framework would be + used +

    [% END %] -
- Add - -
-
- - - - - - - - - [% END %] -
- [% END %] +
+ + [% END %][%# IF (AcqCreateItemReceiving) %] @@ -94,12 +118,15 @@
  • [% IF ( memberfirstname and membersurname ) %][% IF ( memberfirstname ) %][% memberfirstname %][% END %] [% membersurname %][% ELSE %]No name[% END %]
  • [% IF ( edit ) %] - + [% ELSE %] - + [% END %]
  • + [% IF (AcqCreateItemReceiving) %] + + [% ELSE %] [% IF ( quantityreceived ) %] [% IF ( edit ) %] @@ -120,6 +147,7 @@ [% END %] [% END %] + [% END %][%# IF (AcqCreateItemReceiving) %]
  • @@ -135,7 +163,8 @@
    - Cancel + + Cancel
    [% ELSE %]
    --- a/koha-tmpl/intranet-tmpl/prog/en/modules/services/itemrecorddisplay.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/services/itemrecorddisplay.tt @@ -0,0 +1,25 @@ +
      + [% FOREACH iteminfo IN iteminformation %] +
    1. +
      + + [% iteminfo.marc_value %] + + + + + +
      +
    2. + [% END %] +
    + --- a/services/itemrecorddisplay.pl +++ a/services/itemrecorddisplay.pl @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +# Copyright 2011 BibLibre SARL +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +=head1 NAME + +itemrecorddisplay.pl + +=head1 DESCRIPTION + +Return a HTML form for Item record modification or creation. +It uses PrepareItemrecordDisplay + +=cut + +use strict; +use warnings; + +use CGI; +use C4::Auth; +use C4::Output; +use C4::Biblio; + +my $input = new CGI; +my ($template, $loggedinuser, $cookie, $flags) = get_template_and_user( { + template_name => 'services/itemrecorddisplay.tmpl', + query => $input, + type => 'intranet', + authnotrequired => 1, +} ); + +my $biblionumber = $input->param('biblionumber') || ''; +my $itemnumber = $input->param('itemnumber') || ''; +my $frameworkcode = $input->param('frameworkcode') || ''; + +my $result = PrepareItemrecordDisplay($biblionumber, $itemnumber, undef, $frameworkcode); +unless($result) { + $result = PrepareItemrecordDisplay($biblionumber, $itemnumber, undef, ''); +} + +$template->param(%$result); + +output_html_with_http_headers $input, $cookie, $template->output; + --