From 52f1fc16aa9b864e995b82d725d0b4045c591071 Mon Sep 17 00:00:00 2001 From: Olli-Antti Kivilahti Date: Fri, 31 Oct 2014 14:15:15 +0200 Subject: [PATCH] Bug 13182 - When placing an order from a staged file, check for duplicates, display availability information, choose to overlay matched records. When making acquisitions from one staged file, by many branches as a joint effort, it is important to be able to make orders from the same import_record. This places some extra requirements. 1. An status = 'imported' import_record needs to be shown in the stage_file so other branches can order from it as well. So we can't "hide" a import_record from the staged_file after an order is placed. 2. Having imported one import_record, that import_record must know it is matched to the just imported Biblio, so next acquirers know that it is already in our catalog. 3. We need to know which other branches have already ordered the item so we wont end up ordering too many copies of one Biblio to the consortium. Thus we color each row and show the count of Items in the current user's branch and the total amount of Items in the whole consortium. Additional tooltip listing of Item counts by Branch is displayed so we know are there any such Items near us. 4. If we know we already have a matching biblio in Koha, we can optionally overlay the existing Biblio with the new one. (We don't really need it but looks like Bg_12074 needs it). Also a good hook to attach more advanced automatic overlaying/transformation mechanisms. TEST PLAN: SETUP: 0a. Define a Matcher from admin/matching-rules.pl. We think good starting values are: rules, score 020a, 1000 024a, 1000 028a, 1000 245a, 500 240a, 500 110a, 300 100a, 300 Matching threshold 800 0b. Stage a MARC file. 1. Start making an order from a staged_file, stop when you see the import_records after you selected the batch to order from at acqui/addorderiso2709.pl?import_batch_id=50... 2. If you have matches, they are colored and the Item counts are visible. If not, order any item and return to the previous view and reload. 3. Observe that you should now have atleast one match. The match displays the amount of items in your branch, in your consortium, and a tooltip from the record title, showing a breakdown of items by branch. 4. When you add more orders, you get more order lines, but all orders are for the same Biblio, thus you don't get many Biblios, one per order. TODO: Unit tests. TODO: Better test plan. --- C4/ImportBatch.pm | 27 ++++++++++- C4/Items.pm | 25 ++++++++++ acqui/addorderiso2709.pl | 48 +++++++++++++++++--- .../intranet-tmpl/prog/en/css/staff-global.css | 4 ++ .../prog/en/modules/acqui/addorderiso2709.tt | 16 ++++--- 5 files changed, 107 insertions(+), 13 deletions(-) diff --git a/C4/ImportBatch.pm b/C4/ImportBatch.pm index a487cc6..8874bf0 100644 --- a/C4/ImportBatch.pm +++ b/C4/ImportBatch.pm @@ -77,6 +77,7 @@ BEGIN { SetImportRecordStatus GetImportRecordMatches SetImportRecordMatches + SetImportRecordBiblioMatch ); } @@ -1050,7 +1051,7 @@ sub GetImportRecordsRange { my @params; push(@params, $batch_id); if ($status) { - $query .= " AND status=?"; + $query .= " AND status=? OR status='imported'"; push(@params,$status); } @@ -1400,6 +1401,30 @@ sub SetImportRecordMatches { } } +=head SetImportRecordBiblioMatch + + SetImportRecordBiblioMatch( $import_record_id, $biblionumber, [$score] ); + +This sets the given Koha Biblio as a strong match for the given $import_record_id. +This is useful for ex. when you add an item from a staged file. The old import_record persist +and a new Biblio is created as a clone of the import_record. This function stores the strong +relationship between import_record and Biblio. + +@PARAM1 $import_record_id, the koha.import_record.import_record_id +@PARAM2 $biblionumber, the new koha.biblio.biblionumber +@PARAM3 $score, OPTIONAL, the matching score, higher is better. Defaults to 2000000000 + Don't set it unless you have to. +=cut + +sub SetImportRecordBiblioMatch { + my ($import_record_id, $biblionumber, $score) = @_; + + my $matchedBiblioStub; + $matchedBiblioStub->{record_id} = $biblionumber; + $matchedBiblioStub->{score} = ($score) ? $score : 2000000000; #koha.import_record_matches.score int(11) --so (almost) max it! + SetImportRecordMatches( $import_record_id, $matchedBiblioStub ); +} + # internal functions diff --git a/C4/Items.pm b/C4/Items.pm index c23b272..a4575e9 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -64,6 +64,7 @@ BEGIN { GetLostItems GetItemsForInventory GetItemsCount + GetItemsCountByBranch GetItemInfosOf GetItemsByBiblioitemnumber GetItemsInfo @@ -1161,6 +1162,30 @@ sub GetItemsCount { return ($count); } +=head GetItemsCountByBranch + + my $itemcountsByBranch = GetItemsCountByBranch( $biblionumber ); #GROUPS BY the homebranch + my $itemcountsByBranch = GetItemsCountByBranch( $biblionumber, 1 ); #GROUPS BY the holdingbranch + print $itemcountsByBranch->{ $branchcode }->{'count'}; # prints the count as an integer. + +@PARAM1 $biblionumber, koha.biblio.biblionumber of the Biblios whose Items count is desired +@PARAM2 OPTIONAL, Boolean, should we group the counts by homebranch (DEFAULT/FALSE) or the holdingbranch (TRUE) +RETURNS hash of branchcodes with keys homebranch and count +=cut + +sub GetItemsCountByBranch { + my ( $biblionumber, $homeOrHoldingbranch ) = @_; + $homeOrHoldingbranch = ($homeOrHoldingbranch) ? 'holdingbranch' : 'homebranch'; + my $dbh = C4::Context->dbh; + my $query = "SELECT $homeOrHoldingbranch, count(*) AS count + FROM items + WHERE biblionumber=? GROUP BY $homeOrHoldingbranch"; + my $sth = $dbh->prepare($query); + $sth->execute($biblionumber); + my $count = $sth->fetchall_hashref($homeOrHoldingbranch); + return ($count); +} + =head2 GetItemInfosOf GetItemInfosOf(@itemnumbers); diff --git a/acqui/addorderiso2709.pl b/acqui/addorderiso2709.pl index a0fbfd0..196aab6 100755 --- a/acqui/addorderiso2709.pl +++ b/acqui/addorderiso2709.pl @@ -48,6 +48,11 @@ use C4::Members; use Koha::Number::Price; use Koha::Acquisition::Order; +#my $batches = GetAllImportBatches(); +#foreach my $b (@$batches) { +# BatchFindDuplicates($b->{import_batch_id}, C4::Matcher->fetch(1), 1000, 1000, undef); +#} + my $input = new CGI; my ($template, $loggedinuser, $cookie, $userflags) = get_template_and_user({ template_name => "acqui/addorderiso2709.tt", @@ -159,6 +164,7 @@ if ($op eq ""){ my $import_batch_id = $cgiparams->{'import_batch_id'}; my $biblios = GetImportRecordsRange($import_batch_id); my @import_record_id_selected = $input->param("import_record_id"); + my @overlay = $input->param("overlay"); my @quantities = $input->param('quantity'); my @prices = $input->param('price'); my @budgets_id = $input->param('budget_id'); @@ -173,15 +179,16 @@ if ($op eq ""){ my $marcrecord = MARC::Record->new_from_usmarc($marcblob) || die "couldn't translate marc information"; my $match = GetImportRecordMatches( $biblio->{'import_record_id'}, 1 ); my $biblionumber=$#$match > -1?$match->[0]->{'biblionumber'}:0; + my $c_overlay = shift @overlay; my $c_quantity = shift( @quantities ) || GetMarcQuantity($marcrecord, C4::Context->preference('marcflavour') ) || 1; my $c_budget_id = shift( @budgets_id ) || $input->param('all_budget_id') || $budget_id; my $c_discount = shift ( @discount); - $c_discount = $c_discount / 100 if $c_discount > 1; + $c_discount = $c_discount / 100 if $c_discount && $c_discount > 1; my $c_sort1 = shift( @sort1 ) || $input->param('all_sort1') || ''; my $c_sort2 = shift( @sort2 ) || $input->param('all_sort2') || ''; - # 1st insert the biblio, or find it through matcher - unless ( $biblionumber ) { + # INSERT the biblio if no match found, or if we want to overlay the existing match + if ( not($biblionumber) || $c_overlay ) { # add the biblio my $bibitemnum; @@ -196,8 +203,14 @@ if ($op eq ""){ } } } - ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $cgiparams->{'frameworkcode'} || '' ); + ( $biblionumber, $bibitemnum ) = AddBiblio( $marcrecord, $cgiparams->{'frameworkcode'} || '' ) unless $c_overlay; + ModBiblio( $marcrecord, $biblionumber, $cgiparams->{'frameworkcode'} || '' ) if $c_overlay; SetImportRecordStatus( $biblio->{'import_record_id'}, 'imported' ); + + #We need to provide information to koha.import_record_matches to tell Koha that this import_record matches the + #just AddBiblio'd biblio. This is necessary to prevent adding the same import_record to koha.biblio many times. + SetImportRecordBiblioMatch($biblio->{'import_record_id'}, $biblionumber); + # 2nd add authorities if applicable if (C4::Context->preference("BiblioAddsAuthorities")){ my $headings_linked =BiblioAutoLink($marcrecord, $cgiparams->{'frameworkcode'}); @@ -270,8 +283,7 @@ if ($op eq ""){ my @serials = $input->param('serial'); my @indicator = $input->param('indicator'); #Passing the imaginary empty " " -indicators from the templates, to stop C4::Biblio::TransformHtmlToXml() to warn the bejesus out of my koha-error.log my @ind_tag = $input->param('ind_tag'); - my @indicator = $input->param('indicator'); - my $item; + my $item; #WHAT IS THIS MADNESS?? push @{ $item->{tags} }, $tags[0]; push @{ $item->{subfields} }, $subfields[0]; push @{ $item->{field_values} }, $field_values[0]; @@ -403,6 +415,9 @@ sub import_biblios_list { $cellrecord{discount} = $discount || ''; $cellrecord{sort1} = $sort1 || ''; $cellrecord{sort2} = $sort2 || ''; + + get_matched_cellrecord_items( \%cellrecord ); + push @list, \%cellrecord; } @@ -464,6 +479,27 @@ sub add_matcher_list { $template->param(available_matchers => \@matchers); } +#Get the Items already in Koha for this import_record. +#A summary of them is displayed for the user. +sub get_matched_cellrecord_items { + my $cellrecord = shift; + + if ($cellrecord->{match_biblionumber}) { + my $itemsCountByBranch = C4::Items::GetItemsCountByBranch( $cellrecord->{match_biblionumber} ); + my $loginBranchcode = $template->{VARS}->{LoginBranchcode}; + my $totalItemsCount = 0; + my @availabilityMap; + foreach my $homebranch (sort keys %$itemsCountByBranch) { + push (@availabilityMap, $homebranch.' = '.$itemsCountByBranch->{ $homebranch }->{ count }); + $totalItemsCount += $itemsCountByBranch->{ $homebranch }->{ count }; + } + my $loginBranchcount = $itemsCountByBranch->{ $loginBranchcode }->{ count }; + $cellrecord->{loginBranchItemsCount} = $loginBranchcount || '0'; + $cellrecord->{totalItemsCount} = $totalItemsCount; + $cellrecord->{availabilityMap} = join("\n", @availabilityMap); + } +} + sub get_infos_syspref { my ($record, $field_list) = @_; my $syspref = C4::Context->preference('MarcFieldsToOrder'); diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css index 0f67416..cf14b05 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css +++ b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css @@ -2714,3 +2714,7 @@ span.browse-button { #i18nMenu .dropdown-menu a:focus { color : #FFF; } + +.matched_orderline { + background-color: #F0E8F9; +} \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/addorderiso2709.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/addorderiso2709.tt index 1578093..7dca7bb 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/addorderiso2709.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/addorderiso2709.tt @@ -187,9 +187,12 @@ [% FOREACH biblio IN biblio_list %]
- -