View | Details | Raw Unified | Return to bug 4283
Collapse All | Expand All

(-)a/C4/Biblio.pm (+27 lines)
Lines 874-879 sub GetBiblionumberFromItemnumber { Link Here
874
    return ($result);
874
    return ($result);
875
}
875
}
876
876
877
=head2 GetBiblionumberSlice
878
879
    my $biblionumbers = C4::Biblio::GetBiblionumberSlice( 100, 450 );
880
881
@PARAM1 Long, maximum amount of biblio-rows to return. Same as the SQL LIMIT-clause.
882
              Defaults to 0.
883
@PARAM2 Long, how many biblio-rows to skip starting from the first row. Same as the SQL OFFSET-clause.
884
              Defaults to 500.
885
@RETURN Array of Long, a slice of biblionumbers starting from the offset and no more rows than the limit-parameter.
886
=cut
887
888
sub GetBiblionumberSlice {
889
    my ($limit, $offset) = @_;
890
    $limit = ($limit) ? $limit : 500 ;
891
    $offset = ($offset) ? $offset : 0;
892
893
    my $dbh            = C4::Context->dbh;
894
    my $sth            = $dbh->prepare("SELECT biblionumber FROM biblio LIMIT ? OFFSET ?");
895
    $sth->execute($limit, $offset);
896
897
    my @biblionumbers;
898
    while(my $bn = $sth->fetchrow()) {
899
        push @biblionumbers, $bn;
900
    }
901
    return \@biblionumbers;
902
}
903
877
=head2 GetBiblioFromItemNumber
904
=head2 GetBiblioFromItemNumber
878
905
879
  $item = &GetBiblioFromItemNumber($itemnumber,$barcode);
906
  $item = &GetBiblioFromItemNumber($itemnumber,$barcode);
(-)a/cataloguing/deduplicator.pl (+97 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
4
# Copyright 2009 BibLibre
5
# Parts Copyright Catalyst IT 2011
6
#
7
# This file is part of Koha.
8
#
9
# Koha is free software; you can redistribute it and/or modify it under the
10
# terms of the GNU General Public License as published by the Free Software
11
# Foundation; either version 2 of the License, or (at your option) any later
12
# version.
13
#
14
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License along
19
# with Koha; if not, write to the Free Software Foundation, Inc.,
20
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22
use Modern::Perl;
23
use CGI;
24
use C4::Output;
25
use C4::Auth;
26
27
use C4::Matcher;
28
use C4::Items;
29
use C4::Biblio;
30
31
32
my $input = new CGI;
33
34
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
35
    {
36
        template_name   => "cataloguing/deduplicator.tt",
37
        query           => $input,
38
        type            => "intranet",
39
        authnotrequired => 0,
40
        flagsrequired   => { editcatalogue => 'edit_catalogue' },
41
    }
42
);
43
44
my $max_matches = 100;
45
my $matcher_id = $input->param('matcher_id');
46
my $op = $input->param('op');
47
48
#Get the matchers list and set the selected matcher as selected.
49
my @matchers = C4::Matcher::GetMatcherList( $matcher_id );
50
foreach (@matchers) {
51
    if ($matcher_id && $_->{matcher_id} == $matcher_id) {
52
        $_->{selected} = 1;
53
        last();
54
    }
55
}
56
$template->param(   matchers => \@matchers   );
57
58
if ($op && $op eq 'deduplicate') {
59
    my $matcher = C4::Matcher->fetch($matcher_id);
60
    my $biblionumbers = C4::Biblio::GetBiblionumberSlice( $input->param('limit'), $input->param('offset') );
61
62
    my @duplicates;
63
    foreach my $biblionumber (@$biblionumbers) {
64
        my $marc = C4::Biblio::GetMarcBiblio($biblionumber);
65
        my @matches = $matcher->get_matches( $marc, $max_matches );
66
67
        if (scalar(@matches) > 1) {
68
            foreach my $match (@matches) {
69
                my $itemsCount = C4::Items::GetItemsCount($match->{record_id});
70
                $match->{itemsCount} = $itemsCount;
71
            }
72
            my $biblio = buildSlimBiblio($biblionumber, $marc);
73
            $biblio->{matches} = \@matches;
74
75
            push @duplicates, $biblio;
76
        }
77
    }
78
    $template->param(   duplicates => \@duplicates   ) if scalar(@duplicates) > 0;
79
}
80
81
output_html_with_http_headers $input, $cookie, $template->output;
82
83
84
sub buildSlimBiblio {
85
    my ($biblionumber, $marc) = @_;
86
87
    my $biblio = {biblionumber => $biblionumber};
88
    my $title = $marc->subfield('245','a');
89
    $title = $marc->subfield('240','a') unless $title;
90
    my $author = $marc->subfield('100','a');
91
    $author = $marc->subfield('110','a') unless $author;
92
93
    $biblio->{author} = $author;
94
    $biblio->{title} = $title;
95
96
    return $biblio;
97
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbooks.tt (+3 lines)
Lines 73-78 Link Here
73
                [% END %]
73
                [% END %]
74
            </ul>
74
            </ul>
75
        </div>
75
        </div>
76
        <div class="btn-group">
77
            <a href="/cgi-bin/koha/cataloguing/deduplicator.pl"><button class="btn btn-small">Deduplicator</button></a>
78
        </div>
76
  </div>
79
  </div>
77
[% END %]
80
[% END %]
78
81
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/deduplicator.tt (-1 / +135 lines)
Line 0 Link Here
0
- 
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Cataloging &rsaquo; Deduplicator</title>
3
[% INCLUDE 'greybox.inc' %]
4
[% INCLUDE 'doc-head-close.inc' %]
5
<style type="text/css">
6
    /* Prevent floating the main form */
7
    fieldset.rows { float:none; }
8
    .mergeReference { color: #161; font-weight: bold; }
9
    .cell {float: left;}
10
</style>
11
<script type="text/javascript">
12
//<![CDATA[
13
14
    function updateMergereference(self) {
15
        var matchContainer = $(self).parents(".matchContainer");
16
        var checkboxes = $(matchContainer).find('input[id^="checkbox"]');
17
        var mergeReferenceInput = $(matchContainer).parents("form").children("input.mergeReference");
18
        var checkedBoxes = 0;
19
        $(checkboxes).each(function() {
20
            if($(this).attr('checked') === 'checked' ) {
21
                checkedBoxes++;
22
            }
23
        });
24
25
        if (checkedBoxes == 1  &&  $(self).attr('checked') === 'checked') {
26
            $(self).parent().find("span.matchDescription").addClass('mergeReference');
27
            $(mergeReferenceInput).val( $(self).val() ); //Save the biblionumber as the mergereference
28
        }
29
        else if (checkedBoxes == 0) {
30
            $(matchContainer).find("span.matchDescription").removeClass('mergeReference');
31
            $(mergeReferenceInput).val( 0 );
32
        }
33
34
        return 1;
35
    }
36
//]]>
37
</script>
38
</head>
39
<body id="deduplicator">
40
[% INCLUDE 'header.inc' %]
41
[% INCLUDE 'cataloging-search.inc' %]
42
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/cataloguing/addbooks.pl">Cataloging</a>  &rsaquo; Deduplicator</div>
43
44
<div id="doc" class="yui-t7">
45
<div id="bd">
46
    <div id="yui-main">
47
48
49
        <h1>Deduplicator</h1>
50
51
        <div id="deduplicatorForm">
52
            <form name="deduplicationForm" action="/cgi-bin/koha/cataloguing/deduplicator.pl" method="post">
53
                <input type="hidden" name="op" value="deduplicate"/>
54
                <fieldset class="rows">
55
                    <legend>Configure the deduplication search!</legend>
56
                    <ol>
57
                        <li>
58
                            <label>Limit</label><input type="number" name="limit" value="[% limit %]"/><i>How many bibliographic records to deduplicate? Hint: less than 1000.</i>
59
                        </li>
60
                        <li>
61
                            <label>Offset</label><input type="number" name="offset" value="[% offset %]"/><i>From which bibliographic record to start? Hint: increment this by the limit of previous deduplication run. If limit = 200, then first offset is 0, then 200, then 400...</i>
62
                        </li>
63
                        <li>
64
                            <label>Matcher</label>
65
                            <select name="matcher_id" size="1" id="matchers">
66
                            [% FOREACH matcher IN matchers %]
67
                                [% IF ( matcher.selected ) %]
68
                                    <option value="[% matcher.matcher_id %]" selected="selected">[% matcher.code %] - [% matcher.description %]</option>
69
                                [% ELSE %]
70
                                    <option value="[% matcher.matcher_id %]">[% matcher.code %] - [% matcher.description %]</option>
71
                                [% END %]
72
                            [% END %]
73
                            </select>
74
                            <i>The matcher to use to find duplicates. Hint: one can define matchers from the administration menu.</i>
75
                        </li>
76
                        <li>
77
                            <input type="submit" value="Deduplicate!"/>
78
                        </li>
79
                    </ol>
80
                </fieldset>
81
            </form>
82
        </div>
83
84
85
86
[% IF duplicates %]
87
        <div id="duplicatesContainer">
88
            <fieldset class="rows">
89
                <legend>
90
                    List of duplicates
91
                </legend>
92
93
                <label>Matches - Score</label>
94
                <label>Title</label>
95
                <label>Author</label>
96
                <label>Merge</label>
97
                
98
                <ol>
99
                [% FOREACH duplicate IN duplicates %]
100
                    <form name="form[% duplicate.biblionumber %]" action="/cgi-bin/koha/cataloguing/merge.pl" method="post">
101
                        <input type="hidden" class="mergeReference" name="mergereference" value=""/>
102
                        <li>
103
                            <div class="cell">
104
                                <a href="/cgi-bin/koha/catalogue/showmarc.pl?id=[% duplicate.biblionumber %]">[% duplicate.biblionumber %]</a>
105
                                <div class="matchContainer">
106
                                    [% FOREACH match IN duplicate.matches %]
107
                                        <div>
108
                                            <input id="checkbox[% match.record_id %]" name="biblionumber" value="[% match.record_id %]" type="checkbox" onclick="updateMergereference(this)"/>
109
                                            <a href="/cgi-bin/koha/catalogue/showmarc.pl?id=[% match.record_id %]">
110
                                                <span class="matchDescription">
111
                                                    [% match.record_id %] - <i>[% match.score %]</i>
112
                                                </span>
113
                                            </a>
114
                                            <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% match.record_id %]">
115
                                                &nbsp;[[% match.itemsCount %]]
116
                                            </a>
117
                                        </div>
118
                                    [% END %]
119
                                </div>
120
                            </div>
121
                            <div class="cell">[% duplicate.title %]</div>
122
                            <div class="cell">[% duplicate.author %]</div>
123
                            <div class="cell"><input type="submit" value="Merge!"/></div>
124
                        </li>
125
                    </form>
126
                [% END %]
127
                </ol>
128
            </fieldset>
129
        </div><!--<div id="duplicatesContainer">%-->
130
[% END %]
131
    </div>
132
</div> <!--EO <div id="bd"> -->
133
134
135
[% INCLUDE 'intranet-bottom.inc' %]

Return to bug 4283