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

(-)a/Koha/Database/DataInconsistency.pm (-4 / +303 lines)
Lines 1-9 Link Here
1
package Koha::Database::DataInconsistency;
1
package Koha::Database::DataInconsistency;
2
2
3
use Modern::Perl;
3
use Modern::Perl;
4
use C4::Context;
5
use C4::Biblio;
6
use Koha::Biblioitems;
7
use Koha::Biblio::Metadatas;
8
use Koha::BiblioFrameworks;
9
use Koha::Items;
10
use Koha::ItemTypes;
4
use Koha::I18N qw( __x );
11
use Koha::I18N qw( __x );
5
12
6
sub item_library {
13
sub invalid_item_library {
7
    my ( $self, $items ) = @_;
14
    my ( $self, $items ) = @_;
8
15
9
    $items = $items->search( { -or => { homebranch => undef, holdingbranch => undef } } );
16
    $items = $items->search( { -or => { homebranch => undef, holdingbranch => undef } } );
Lines 32-42 sub item_library { Link Here
32
    return @errors;
39
    return @errors;
33
}
40
}
34
41
35
sub for_biblio {
42
sub ids {
36
    my ( $self, $biblio ) = @_;
43
    my ( $self, $object ) = @_;
44
    if ( $object->can('_resultset') ) {
45
46
        # It's a Koha::Objects
47
        return [ $object->get_column('biblionumber') ];
48
    } else {
49
50
        # It's a single Koha::Object
51
        return [ $object->biblionumber ];
52
    }
53
}
54
55
sub no_item_type {
56
    my ( $self, $biblios ) = @_;
57
    my $ids = $self->ids($biblios);
37
    my @errors;
58
    my @errors;
38
    push @errors, $self->item_library( $biblio->items );
59
    if ( C4::Context->preference('item-level_itypes') ) {
60
        my $items_without_itype = Koha::Items->search(
61
            {
62
                biblionumber => $ids,
63
                -or          => [ itype => undef, itype => '' ]
64
            }
65
        );
66
        if ( $items_without_itype->count ) {
67
            while ( my $item = $items_without_itype->next ) {
68
                if ( defined $item->biblioitem->itemtype && $item->biblioitem->itemtype ne '' ) {
69
                    push @errors, __x(
70
                        "Item with itemnumber={itemnumber} does not have a itype value, biblio's item type will be used ({itemtype})",
71
                        itemnumber => $item->itemnumber,
72
                        itemtype   => $item->biblioitem->itemtype,
73
                    );
74
                } else {
75
                    push @errors, __x(
76
                        "Item with itemnumber={itemnumber} does not have a itype value, additionally no item type defined for biblionumber={biblionumber}",
77
                        itemnumber   => $item->itemnumber,
78
                        biblionumber => $item->biblioitem->biblionumber,
79
                    );
80
                }
81
            }
82
        }
83
    } else {
84
        my $biblioitems_without_itemtype = Koha::Biblioitems->search( { biblionumber => $ids, itemtype => undef } );
85
        if ( $biblioitems_without_itemtype->count ) {
86
            while ( my $biblioitem = $biblioitems_without_itemtype->next ) {
87
                push @errors, __x(
88
                    "Biblioitem with biblioitemnumber={biblioitemnumber} does not have a itemtype value",
89
                    biblioitemnumber => $biblioitem->biblioitemnumber,
90
                );
91
            }
92
        }
93
    }
94
    return @errors;
95
}
96
97
sub invalid_item_type {
98
    my ( $self, $biblios ) = @_;
99
    my $ids = $self->ids($biblios);
100
    my @errors;
101
    my @itemtypes = Koha::ItemTypes->search->get_column('itemtype');
102
    if ( C4::Context->preference('item-level_itypes') ) {
103
        my $items_with_invalid_itype = Koha::Items->search(
104
            {
105
                biblionumber => $ids,
106
                -and         => [ itype => { not_in => \@itemtypes }, itype => { '!=' => '' } ]
107
            }
108
        );
109
        if ( $items_with_invalid_itype->count ) {
110
            while ( my $item = $items_with_invalid_itype->next ) {
111
                push @errors, __x(
112
                    "Item with itemnumber={itemnumber}, biblionumber={biblionumber} does not have a valid itype value ({itype})",
113
                    itemnumber   => $item->itemnumber,
114
                    biblionumber => $item->biblionumber,
115
                    itype        => $item->itype,
116
                );
117
            }
118
        }
119
    } else {
120
        my $biblioitems_with_invalid_itemtype =
121
            Koha::Biblioitems->search( { biblionumber => $ids, itemtype => { not_in => \@itemtypes } } );
122
        if ( $biblioitems_with_invalid_itemtype->count ) {
123
            while ( my $biblioitem = $biblioitems_with_invalid_itemtype->next ) {
124
                push @errors, __x(
125
                    "Biblioitem with biblioitemnumber={biblioitemnumber} does not have a valid itemtype value",
126
                    biblioitemnumber => $biblioitem->biblioitemnumber,
127
                );
128
            }
129
        }
130
    }
39
    return @errors;
131
    return @errors;
40
}
132
}
41
133
134
sub errors_in_marc {
135
    my ( $self, $biblios ) = @_;
136
    my $ids = $self->ids($biblios);
137
    my @item_fields_in_marc;
138
    my $errors;
139
    my ( $item_tag, $item_subfield ) = C4::Biblio::GetMarcFromKohaField("items.itemnumber");
140
    my $search_string = q{ExtractValue(metadata,'count(//datafield[@tag="} . $item_tag . q{"])')>0};
141
    my $biblio_metadatas_with_item_fields =
142
        Koha::Biblio::Metadatas->search( { biblionumber => $ids } )->search( \$search_string );
143
    if ( $biblio_metadatas_with_item_fields->count ) {
144
        while ( my $biblio_metadata_with_item_fields = $biblio_metadatas_with_item_fields->next ) {
145
            push @item_fields_in_marc,
146
                {
147
                biblionumber => $biblio_metadata_with_item_fields->biblionumber,
148
                };
149
        }
150
    }
151
152
    my ( $biblio_tag,      $biblio_subfield )     = C4::Biblio::GetMarcFromKohaField("biblio.biblionumber");
153
    my ( $biblioitem_tag,  $biblioitem_subfield ) = C4::Biblio::GetMarcFromKohaField("biblioitems.biblioitemnumber");
154
    $biblios = Koha::Biblios->search( { biblionumber => $ids } );
155
    while ( my $biblio = $biblios->next ) {
156
        my $record = eval { $biblio->metadata->record; };
157
        if ($@) {
158
            push @{ $errors->{decoding_errors} }, $@;
159
            next;
160
        }
161
        my ( $biblionumber, $biblioitemnumber );
162
        if ( $biblio_tag < 10 ) {
163
            my $biblio_control_field = $record->field($biblio_tag);
164
            $biblionumber = $biblio_control_field->data if $biblio_control_field;
165
        } else {
166
            $biblionumber = $record->subfield( $biblio_tag, $biblio_subfield );
167
        }
168
        if ( $biblioitem_tag < 10 ) {
169
            my $biblioitem_control_field = $record->field($biblioitem_tag);
170
            $biblioitemnumber = $biblioitem_control_field->data if $biblioitem_control_field;
171
        } else {
172
            $biblioitemnumber = $record->subfield( $biblioitem_tag, $biblioitem_subfield );
173
        }
174
        if ( $biblionumber != $biblio->biblionumber ) {
175
                push @{ $errors->{ids_not_in_marc} },
176
                    __x(
177
                    q{Biblionumber {biblionumber} has '{biblionumber_in_marc}' in {biblio_tag}${biblio_subfield}},
178
                    biblionumber         => $biblio->biblionumber,
179
                    biblionumber_in_marc => $biblionumber,
180
                    biblio_tag           => $biblio_tag,
181
                    biblio_subfield      => $biblio_subfield,
182
                    );
183
184
        }
185
        if ( $biblioitemnumber != $biblio->biblioitem->biblioitemnumber ) {
186
                push @{ $errors->{ids_not_in_marc} },
187
                    __x(
188
                    q{Biblionumber {biblionumber} has biblioitemnumber '{biblioitemnumber}' but should be '{biblioitemnumber_in_marc}' in {biblioitem_tag}${biblioitem_subfield}},
189
                    biblionumber             => $biblio->biblionumber,
190
                    biblioitemnumber         => $biblio->biblioitem->biblioitemnumber,
191
                    biblioitemnumber_in_marc => $biblionumber,
192
                    biblioitem_tag           => $biblioitem_tag,
193
                    biblioitem_subfield      => $biblioitem_subfield,
194
                    );
195
            }
196
        }
197
    }
198
    if (@item_fields_in_marc) {
199
        for my $biblionumber (@item_fields_in_marc) {
200
            push @{ $errors->{item_fields_in_marc} },
201
                __x(
202
                q{Biblionumber {biblionumber} has item fields ({item_tag}) in the marc record},
203
                biblionumber => $biblionumber->{biblionumber},
204
                item_tag     => $item_tag,
205
                );
206
        }
207
    }
208
209
    return $errors;
210
}
211
212
sub nonexistent_AV {
213
    my ( $self, $biblios ) = @_;
214
    my $ids = $self->ids($biblios);
215
    my @errors;
216
    my @framework_codes = Koha::BiblioFrameworks->search()->get_column('frameworkcode');
217
    push @framework_codes, "";    # The default is not stored in frameworks, we need to force it
218
219
    my $invalid_av_per_framework = {};
220
    foreach my $frameworkcode (@framework_codes) {
221
222
        # We are only checking fields that are mapped to DB fields
223
        my $msss = Koha::MarcSubfieldStructures->search(
224
            {
225
                frameworkcode    => $frameworkcode,
226
                authorised_value => { '!=' => [ -and => ( undef, '' ) ] },
227
                kohafield        => { '!=' => [ -and => ( undef, '' ) ] }
228
            }
229
        );
230
        while ( my $mss = $msss->next ) {
231
            my $kohafield = $mss->kohafield;
232
            my $av        = $mss->authorised_value;
233
            next if grep { $_ eq $av } qw( branches itemtypes cn_source );    # internal categories
234
235
            my $avs = Koha::AuthorisedValues->search_by_koha_field(
236
                {
237
                    frameworkcode => $frameworkcode,
238
                    kohafield     => $kohafield,
239
                }
240
            );
241
            my $tmp_kohafield = $kohafield;
242
            if ( $tmp_kohafield =~ /^biblioitems/ ) {
243
                $tmp_kohafield =~ s|biblioitems|biblioitem|;
244
            } else {
245
                $tmp_kohafield =~ s|items|me|;
246
            }
247
248
            # replace items.attr with me.attr
249
250
            # We are only checking biblios with items
251
            my $items = Koha::Items->search(
252
                {
253
                    'me.biblionumber' => $ids,
254
                    $tmp_kohafield    => {
255
                        -not_in => [ $avs->get_column('authorised_value'), '' ],
256
                        '!='    => undef,
257
                    },
258
                    'biblio.frameworkcode' => $frameworkcode
259
                },
260
                { join => [ 'biblioitem', 'biblio' ] }
261
            );
262
            if ( $items->count ) {
263
                $invalid_av_per_framework->{$frameworkcode}->{$av} =
264
                    { items => $items, kohafield => $kohafield };
265
            }
266
        }
267
    }
268
    if (%$invalid_av_per_framework) {
269
        for my $frameworkcode ( keys %$invalid_av_per_framework ) {
270
            while ( my ( $av_category, $v ) = each %{ $invalid_av_per_framework->{$frameworkcode} } ) {
271
                my $items     = $v->{items};
272
                my $kohafield = $v->{kohafield};
273
                my ( $table, $column ) = split '\.', $kohafield;
274
                my $output;
275
                while ( my $i = $items->next ) {
276
                    my $value =
277
                          $table eq 'items'  ? $i->$column
278
                        : $table eq 'biblio' ? $i->biblio->$column
279
                        :                      $i->biblioitem->$column;
280
                    $output .= " {" . $i->itemnumber . " => " . $value . "}\n";
281
                }
282
                push @errors, __x(
283
                          "The Framework *{frameworkcode}* is using the authorised value's category *{av_category}*, "
284
                        . "but the following {kohafield} do not have a value defined ({itemnumber => value }):\n{output}",
285
                    frameworkcode => $frameworkcode,
286
                    av_category   => $av_category,
287
                    kohafield     => $kohafield,
288
                    output        => $output,
289
                );
290
            }
291
        }
292
    }
293
    return @errors;
294
}
295
296
sub empty_title {
297
    my ( $self, $biblios ) = @_;
298
    my $ids = $self->ids($biblios);
299
    my @errors;
300
    $biblios = Koha::Biblios->search(
301
        {
302
            biblionumber => $ids,
303
            -or          => [
304
                title => '',
305
                title => undef,
306
            ]
307
        }
308
    );
309
    if ( $biblios->count ) {
310
        while ( my $biblio = $biblios->next ) {
311
            push @errors,
312
                __x(
313
                "Biblio with biblionumber={biblionumber} does not have title defined",
314
                biblionumber => $biblio->biblionumber
315
                );
316
        }
317
    }
318
    return @errors;
319
}
320
321
sub for_biblio {
322
    my ( $self, $biblio ) = @_;
323
    my @invalid_item_library = $self->invalid_item_library( $biblio->items );
324
    my @no_item_type         = $self->no_item_type($biblio);
325
    my @invalid_item_type    = $self->invalid_item_type($biblio);
326
    my $errors_in_marc       = $self->errors_in_marc($biblio);
327
    my @nonexistent_AV       = $self->nonexistent_AV($biblio);
328
    my @empty_title          = $self->empty_title($biblio);
329
    return {
330
        invalid_item_library => \@invalid_item_library,
331
        no_item_type         => \@no_item_type,
332
        invalid_item_type    => \@invalid_item_type,
333
        decoding_errors      => $errors_in_marc->{decoding_errors}     || [],
334
        ids_not_in_marc      => $errors_in_marc->{ids_not_in_marc}     || [],
335
        item_fields_in_marc  => $errors_in_marc->{item_fields_in_marc} || [],
336
        nonexistent_AV       => \@nonexistent_AV,
337
        empty_title          => \@empty_title,
338
    };
339
}
340
42
1;
341
1;
(-)a/catalogue/detail.pl (-2 / +2 lines)
Lines 540-549 $template->param( found1 => scalar $query->param('found1') ); Link Here
540
$template->param( biblio => $biblio );
540
$template->param( biblio => $biblio );
541
541
542
if ( $query->param('audit') ) {
542
if ( $query->param('audit') ) {
543
    my @audit_errors = Koha::Database::DataInconsistency->for_biblio($biblio);
543
    my $audit_errors = Koha::Database::DataInconsistency->for_biblio($biblio);
544
    $template->param(
544
    $template->param(
545
        auditing     => 1,
545
        auditing     => 1,
546
        audit_errors => \@audit_errors,
546
        audit_errors => [ map { scalar @{ $audit_errors->{$_} } ? $audit_errors->{$_} : () } keys %$audit_errors ],
547
    );
547
    );
548
}
548
}
549
549
(-)a/misc/maintenance/search_for_data_inconsistencies.pl (-235 / +41 lines)
Lines 31-42 use Koha::Database::DataInconsistency; Link Here
31
31
32
{
32
{
33
    my $items  = Koha::Items->search;
33
    my $items  = Koha::Items->search;
34
    my @errors = Koha::Database::DataInconsistency->item_library($items);
34
    my @errors = Koha::Database::DataInconsistency->invalid_item_library($items);
35
    if (@errors) {
35
    if (@errors) {
36
        new_section("Not defined items.homebranch and/or items.holdingbranch");
36
        new_section("Not defined items.homebranch and/or items.holdingbranch");
37
        for my $error (@errors) {
37
        new_item($_) for @errors;
38
            new_item($error);
39
        }
40
    }
38
    }
41
    if (@errors) { new_hint("Edit these items and set valid homebranch and/or holdingbranch") }
39
    if (@errors) { new_hint("Edit these items and set valid homebranch and/or holdingbranch") }
42
}
40
}
Lines 56-325 use Koha::Database::DataInconsistency; Link Here
56
}
54
}
57
55
58
{
56
{
59
    if ( C4::Context->preference('item-level_itypes') ) {
57
    my $biblios = Koha::Biblios->search;
60
        my $items_without_itype = Koha::Items->search( { -or => [ itype => undef, itype => '' ] } );
58
    my @errors  = Koha::Database::DataInconsistency->no_item_type($biblios);
61
        if ( $items_without_itype->count ) {
59
    if (@errors) {
60
        if ( C4::Context->preference('item-level_itypes') ) {
62
            new_section("Items do not have itype defined");
61
            new_section("Items do not have itype defined");
63
            while ( my $item = $items_without_itype->next ) {
62
            new_item($_) for @errors;
64
                if ( defined $item->biblioitem->itemtype && $item->biblioitem->itemtype ne '' ) {
65
                    new_item(
66
                        sprintf
67
                            "Item with itemnumber=%s does not have a itype value, biblio's item type will be used (%s)",
68
                        $item->itemnumber, $item->biblioitem->itemtype
69
                    );
70
                } else {
71
                    new_item(
72
                        sprintf
73
                            "Item with itemnumber=%s does not have a itype value, additionally no item type defined for biblionumber=%s",
74
                        $item->itemnumber, $item->biblioitem->biblionumber
75
                    );
76
                }
77
            }
78
            new_hint("The system preference item-level_itypes expects item types to be defined at item level");
63
            new_hint("The system preference item-level_itypes expects item types to be defined at item level");
79
        }
64
        } else {
80
    } else {
81
        my $biblioitems_without_itemtype = Koha::Biblioitems->search( { itemtype => undef } );
82
        if ( $biblioitems_without_itemtype->count ) {
83
            new_section("Biblioitems do not have itemtype defined");
65
            new_section("Biblioitems do not have itemtype defined");
84
            while ( my $biblioitem = $biblioitems_without_itemtype->next ) {
66
            new_item($_) for @errors;
85
                new_item(
86
                    sprintf "Biblioitem with biblioitemnumber=%s does not have a itemtype value",
87
                    $biblioitem->biblioitemnumber
88
                );
89
            }
90
            new_hint("The system preference item-level_itypes expects item types to be defined at biblio level");
67
            new_hint("The system preference item-level_itypes expects item types to be defined at biblio level");
91
        }
68
        }
92
    }
69
    }
93
70
94
    my @itemtypes = Koha::ItemTypes->search->get_column('itemtype');
71
    $biblios = Koha::Biblios->search;
95
    if ( C4::Context->preference('item-level_itypes') ) {
72
    @errors  = Koha::Database::DataInconsistency->invalid_item_type($biblios);
96
        my $items_with_invalid_itype =
73
    if (@errors) {
97
            Koha::Items->search( { -and => [ itype => { not_in => \@itemtypes }, itype => { '!=' => '' } ] } );
74
        if ( C4::Context->preference('item-level_itypes') ) {
98
        if ( $items_with_invalid_itype->count ) {
99
            new_section("Items have invalid itype defined");
75
            new_section("Items have invalid itype defined");
100
            while ( my $item = $items_with_invalid_itype->next ) {
76
            new_item($_) for @errors;
101
                new_item(
102
                    sprintf "Item with itemnumber=%s, biblionumber=%s does not have a valid itype value (%s)",
103
                    $item->itemnumber, $item->biblionumber, $item->itype
104
                );
105
            }
106
            new_hint(
77
            new_hint(
107
                "The items must have a itype value that is defined in the item types of Koha (Home › Administration › Item types administration)"
78
                "The items must have a itype value that is defined in the item types of Koha (Home › Administration › Item types administration)"
108
            );
79
            );
109
        }
80
        } else {
110
    } else {
111
        my $biblioitems_with_invalid_itemtype = Koha::Biblioitems->search( { itemtype => { not_in => \@itemtypes } } );
112
        if ( $biblioitems_with_invalid_itemtype->count ) {
113
            new_section("Biblioitems do not have itemtype defined");
81
            new_section("Biblioitems do not have itemtype defined");
114
            while ( my $biblioitem = $biblioitems_with_invalid_itemtype->next ) {
82
            new_item($_) for @errors;
115
                new_item(
116
                    sprintf "Biblioitem with biblioitemnumber=%s does not have a valid itemtype value",
117
                    $biblioitem->biblioitemnumber
118
                );
119
            }
120
            new_hint(
83
            new_hint(
121
                "The biblioitems must have a itemtype value that is defined in the item types of Koha (Home › Administration › Item types administration)"
84
                "The biblioitems must have a itemtype value that is defined in the item types of Koha (Home › Administration › Item types administration)"
122
            );
85
            );
123
        }
86
        }
124
    }
87
    }
125
88
126
    my @item_fields_in_marc;
89
    $biblios = Koha::Biblios->search;
127
    my ( $item_tag, $item_subfield ) = C4::Biblio::GetMarcFromKohaField("items.itemnumber");
90
    my $errors = Koha::Database::DataInconsistency->errors_in_marc($biblios);
128
    my $search_string                     = q{ExtractValue(metadata,'count(//datafield[@tag="} . $item_tag . q{"])')>0};
91
    if ( $errors && %$errors ) {
129
    my $biblio_metadatas_with_item_fields = Koha::Biblio::Metadatas->search( \$search_string );
92
        if ( exists $errors->{decoding_errors} ) {
130
    if ( $biblio_metadatas_with_item_fields->count ) {
93
            new_section("Bibliographic records have invalid MARCXML");
131
        while ( my $biblio_metadata_with_item_fields = $biblio_metadatas_with_item_fields->next ) {
94
            new_item($_) for @{ $errors->{decoding_errors} };
132
            push @item_fields_in_marc,
95
            new_hint(
133
                {
96
                "The bibliographic records must have a valid MARCXML or you will face encoding issues or wrong displays"
134
                biblionumber => $biblio_metadata_with_item_fields->biblionumber,
97
            );
135
                };
136
        }
137
    }
138
139
    my ( @decoding_errors, @ids_not_in_marc );
140
    my $biblios = Koha::Biblios->search;
141
    my ( $biblio_tag,     $biblio_subfield )     = C4::Biblio::GetMarcFromKohaField("biblio.biblionumber");
142
    my ( $biblioitem_tag, $biblioitem_subfield ) = C4::Biblio::GetMarcFromKohaField("biblioitems.biblioitemnumber");
143
    while ( my $biblio = $biblios->next ) {
144
        my $record = eval { $biblio->metadata->record; };
145
        if ($@) {
146
            push @decoding_errors, $@;
147
            next;
148
        }
149
        my ( $biblionumber, $biblioitemnumber );
150
        if ( $biblio_tag < 10 ) {
151
            my $biblio_control_field = $record->field($biblio_tag);
152
            $biblionumber = $biblio_control_field->data if $biblio_control_field;
153
        } else {
154
            $biblionumber = $record->subfield( $biblio_tag, $biblio_subfield );
155
        }
156
        if ( $biblioitem_tag < 10 ) {
157
            my $biblioitem_control_field = $record->field($biblioitem_tag);
158
            $biblioitemnumber = $biblioitem_control_field->data if $biblioitem_control_field;
159
        } else {
160
            $biblioitemnumber = $record->subfield( $biblioitem_tag, $biblioitem_subfield );
161
        }
162
        if ( $biblionumber != $biblio->biblionumber ) {
163
            push @ids_not_in_marc,
164
                {
165
                biblionumber         => $biblio->biblionumber,
166
                biblionumber_in_marc => $biblionumber,
167
                };
168
        }
169
        if ( $biblioitemnumber != $biblio->biblioitem->biblioitemnumber ) {
170
            push @ids_not_in_marc,
171
                {
172
                biblionumber             => $biblio->biblionumber,
173
                biblioitemnumber         => $biblio->biblioitem->biblioitemnumber,
174
                biblioitemnumber_in_marc => $biblionumber,
175
                };
176
        }
98
        }
177
    }
99
        if ( exists $errors->{ids_not_in_marc} ) {
178
    if (@decoding_errors) {
100
            new_section("Bibliographic records have MARCXML without biblionumber or biblioitemnumber");
179
        new_section("Bibliographic records have invalid MARCXML");
101
            new_item($_) for @{ $errors->{ids_not_in_marc} };
180
        new_item($_) for @decoding_errors;
102
            new_hint("The bibliographic records must have the biblionumber and biblioitemnumber in MARCXML");
181
        new_hint(
182
            "The bibliographic records must have a valid MARCXML or you will face encoding issues or wrong displays");
183
    }
184
    if (@ids_not_in_marc) {
185
        new_section("Bibliographic records have MARCXML without biblionumber or biblioitemnumber");
186
        for my $id (@ids_not_in_marc) {
187
            if ( exists $id->{biblioitemnumber} ) {
188
                new_item(
189
                    sprintf(
190
                        q{Biblionumber %s has biblioitemnumber '%s' but should be '%s' in %s$%s},
191
                        $id->{biblionumber},
192
                        $id->{biblioitemnumber},
193
                        $id->{biblioitemnumber_in_marc},
194
                        $biblioitem_tag,
195
                        $biblioitem_subfield,
196
                    )
197
                );
198
            } else {
199
                new_item(
200
                    sprintf(
201
                        q{Biblionumber %s has '%s' in %s$%s},
202
                        $id->{biblionumber},
203
                        $id->{biblionumber_in_marc},
204
                        $biblio_tag,
205
                        $biblio_subfield,
206
                    )
207
                );
208
            }
209
        }
103
        }
210
        new_hint("The bibliographic records must have the biblionumber and biblioitemnumber in MARCXML");
104
        if ( exists $errors->{item_fields_in_marc} ) {
211
    }
105
            new_section("Bibliographic records have item fields in the MARC");
212
    if (@item_fields_in_marc) {
106
            new_item($_) for @{ $errors->{item_fields_in_marc} };
213
        new_section("Bibliographic records have item fields in the MARC");
107
            new_hint("You can fix these by running misc/maintenance/touch_all_biblios.pl");
214
        for my $biblionumber (@item_fields_in_marc) {
215
            new_item(
216
                sprintf(
217
                    q{Biblionumber %s has item fields (%s) in the marc record},
218
                    $biblionumber->{biblionumber},
219
                    $item_tag,
220
                )
221
            );
222
        }
108
        }
223
        new_hint("You can fix these by running misc/maintenance/touch_all_biblios.pl");
224
    }
109
    }
225
}
110
}
226
111
227
{
112
{
228
    my @framework_codes = Koha::BiblioFrameworks->search()->get_column('frameworkcode');
113
    my $biblios = Koha::Biblios->search;
229
    push @framework_codes, "";    # The default is not stored in frameworks, we need to force it
114
    my @errors  = Koha::Database::DataInconsistency->nonexistent_AV($biblios);
230
115
    if (@errors) {
231
    my $invalid_av_per_framework = {};
232
    foreach my $frameworkcode (@framework_codes) {
233
234
        # We are only checking fields that are mapped to DB fields
235
        my $msss = Koha::MarcSubfieldStructures->search(
236
            {
237
                frameworkcode    => $frameworkcode,
238
                authorised_value => { '!=' => [ -and => ( undef, '' ) ] },
239
                kohafield        => { '!=' => [ -and => ( undef, '' ) ] }
240
            }
241
        );
242
        while ( my $mss = $msss->next ) {
243
            my $kohafield = $mss->kohafield;
244
            my $av        = $mss->authorised_value;
245
            next if grep { $_ eq $av } qw( branches itemtypes cn_source );    # internal categories
246
247
            my $avs = Koha::AuthorisedValues->search_by_koha_field(
248
                {
249
                    frameworkcode => $frameworkcode,
250
                    kohafield     => $kohafield,
251
                }
252
            );
253
            my $tmp_kohafield = $kohafield;
254
            if ( $tmp_kohafield =~ /^biblioitems/ ) {
255
                $tmp_kohafield =~ s|biblioitems|biblioitem|;
256
            } else {
257
                $tmp_kohafield =~ s|items|me|;
258
            }
259
260
            # replace items.attr with me.attr
261
262
            # We are only checking biblios with items
263
            my $items = Koha::Items->search(
264
                {
265
                    $tmp_kohafield => {
266
                        -not_in => [ $avs->get_column('authorised_value'), '' ],
267
                        '!='    => undef,
268
                    },
269
                    'biblio.frameworkcode' => $frameworkcode
270
                },
271
                { join => [ 'biblioitem', 'biblio' ] }
272
            );
273
            if ( $items->count ) {
274
                $invalid_av_per_framework->{$frameworkcode}->{$av} =
275
                    { items => $items, kohafield => $kohafield };
276
            }
277
        }
278
    }
279
    if (%$invalid_av_per_framework) {
280
        new_section('Wrong values linked to authorised values');
116
        new_section('Wrong values linked to authorised values');
281
        for my $frameworkcode ( keys %$invalid_av_per_framework ) {
117
        new_item($_) for @errors;
282
            while ( my ( $av_category, $v ) = each %{ $invalid_av_per_framework->{$frameworkcode} } ) {
283
                my $items     = $v->{items};
284
                my $kohafield = $v->{kohafield};
285
                my ( $table, $column ) = split '\.', $kohafield;
286
                my $output;
287
                while ( my $i = $items->next ) {
288
                    my $value =
289
                          $table eq 'items'  ? $i->$column
290
                        : $table eq 'biblio' ? $i->biblio->$column
291
                        :                      $i->biblioitem->$column;
292
                    $output .= " {" . $i->itemnumber . " => " . $value . "}\n";
293
                }
294
                new_item(
295
                    sprintf(
296
                              "The Framework *%s* is using the authorised value's category *%s*, "
297
                            . "but the following %s do not have a value defined ({itemnumber => value }):\n%s",
298
                        $frameworkcode, $av_category, $kohafield, $output
299
                    )
300
                );
301
            }
302
        }
303
    }
118
    }
304
}
119
}
305
120
306
{
121
{
307
    my $biblios = Koha::Biblios->search(
122
    my $biblios = Koha::Biblios->search;
308
        {
123
    my @errors  = Koha::Database::DataInconsistency->empty_title($biblios);
309
            -or => [
124
    if (@errors) {
310
                title => '',
311
                title => undef,
312
            ]
313
        }
314
    );
315
    if ( $biblios->count ) {
316
        my ( $title_tag, $title_subtag ) = C4::Biblio::GetMarcFromKohaField('biblio.title');
125
        my ( $title_tag, $title_subtag ) = C4::Biblio::GetMarcFromKohaField('biblio.title');
317
        my $title_field = $title_tag // '';
126
        my $title_field = $title_tag // '';
318
        $title_field .= '$' . $title_subtag if $title_subtag;
127
        $title_field .= '$' . $title_subtag if $title_subtag;
319
        new_section("Biblio without title $title_field");
128
        new_section("Biblio without title $title_field");
320
        while ( my $biblio = $biblios->next ) {
129
        new_item($_) for @errors;
321
            new_item( sprintf "Biblio with biblionumber=%s does not have title defined", $biblio->biblionumber );
322
        }
323
        new_hint("Edit these bibliographic records to define a title");
130
        new_hint("Edit these bibliographic records to define a title");
324
    }
131
    }
325
}
132
}
326
- 

Return to bug 40777