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

(-)a/misc/maintenance/search_for_data_inconsistencies.pl (-199 / +283 lines)
Lines 16-22 Link Here
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
20
use Koha::Script;
19
use Koha::Script;
21
use Koha::AuthorisedValues;
20
use Koha::AuthorisedValues;
22
use Koha::Authorities;
21
use Koha::Authorities;
Lines 27-49 use Koha::Items; Link Here
27
use Koha::ItemTypes;
26
use Koha::ItemTypes;
28
use Koha::Patrons;
27
use Koha::Patrons;
29
use C4::Biblio qw( GetMarcFromKohaField );
28
use C4::Biblio qw( GetMarcFromKohaField );
29
use Getopt::Long;
30
use Pod::Usage;
31
32
our %options = (
33
    'check-branch'    => 0,
34
    'check-auth'      => 0,
35
    'check-status'    => 0,
36
    'check-framework' => 0,
37
    'check-title'     => 0,
38
    'check-age'       => 0,
39
    'skip-branch'     => 1,
40
    'skip-auth'       => 1,
41
    'skip-status'     => 1,
42
    'skip-framework'  => 1,
43
    'skip-title'      => 1,
44
    'skip-age'        => 1,
45
    'help'            => 0,
46
);
47
48
# Parse command line options
49
GetOptions(
50
    'check-branch'    => sub { $options{'check-branch'}    = 1 },
51
    'check-auth'      => sub { $options{'check-auth'}      = 1 },
52
    'check-status'    => sub { $options{'check-status'}    = 1 },
53
    'check-framework' => sub { $options{'check-framework'} = 1 },
54
    'check-title'     => sub { $options{'check-title'}     = 1 },
55
    'check-age'       => sub { $options{'check-age'}       = 1 },
56
    'skip-branch'     => sub { $options{'skip-branch'}     = 0 },
57
    'skip-auth'       => sub { $options{'skip-auth'}       = 0 },
58
    'skip-status'     => sub { $options{'skip-status'}     = 0 },
59
    'skip-framework'  => sub { $options{'skip-framework'}  = 0 },
60
    'skip-title'      => sub { $options{'skip-title'}      = 0 },
61
    'skip-age'        => sub { $options{'skip-age'}        = 0 },
62
    'help'            => sub { $options{'help'}            = 1; },
63
) or pod2usage(2);    # Print usage if invalid options are provided
64
65
# Call handle_invalid_options subroutine if invalid options are provided
66
Getopt::Long::Configure('pass_through');
67
GetOptions(
68
    '<>' => sub {
69
        my ($opt_name) = @_;
70
        handle_invalid_options($opt_name);
71
    }
72
);
73
74
# Print usage and exit if --help flag is provided
75
pod2usage(1) if $options{'help'};
76
77
# Run tests based on options
78
set_skip_options();
79
CheckItemsBranch()     if $options{'check-branch'}    || $options{'skip-branch'};
80
CheckItemsAuthHeader() if $options{'check-auth'}      || $options{'skip-auth'};
81
CheckItemsStatus()     if $options{'check-status'}    || $options{'skip-status'};
82
CheckItemsFramework()  if $options{'check-framework'} || $options{'skip-framework'};
83
CheckItemsTitle()      if $options{'check-title'}     || $options{'skip-title'};
84
CheckAgeForCategory()  if $options{'check-age'}       || $options{'skip-age'};
85
86
# Handle invalid options
87
sub handle_invalid_options {
88
    my ($opt_name) = @_;
89
    print "Invalid option provided: $opt_name\n";
90
    pod2usage(2);
91
}
30
92
31
{
93
# Set skip options based on check options
94
sub set_skip_options {
95
    my $has_check_option = grep { $options{$_} == 1 } grep { /^check-/ } keys %options;
96
    if ($has_check_option) {
97
        foreach my $key (keys %options) {
98
            $options{$key} = 0 if $key =~ /^skip-/;
99
        }
100
    }
101
    return %options;
102
}
103
104
sub CheckItemsBranch {
32
    my $items = Koha::Items->search({ -or => { homebranch => undef, holdingbranch => undef }});
105
    my $items = Koha::Items->search({ -or => { homebranch => undef, holdingbranch => undef }});
33
    if ( $items->count ) { new_section("Not defined items.homebranch and/or items.holdingbranch")}
106
    if ( $items->count ) { new_section("Not defined items.homebranch and/or items.holdingbranch")}
34
    while ( my $item = $items->next ) {
107
    while ( my $item = $items->next ) {
35
        if ( not $item->homebranch and not $item->holdingbranch ) {
108
        if ( not $item->homebranch and not $item->holdingbranch ) {
36
            new_item(sprintf "Item with itemnumber=%s does not have homebranch and holdingbranch defined", $item->itemnumber);
109
            new_item(sprintf "Item with itemnumber=%s and biblionumber=%s does not have homebranch and holdingbranch defined",  $item->itemnumber, $item->biblionumber);
37
        } elsif ( not $item->homebranch ) {
110
            } elsif ( not $item->homebranch ) {
38
            new_item(sprintf "Item with itemnumber=%s does not have homebranch defined", $item->itemnumber);
111
            new_item(sprintf "Item with itemnumber=%s and biblionumber=%s does not have homebranch defined", $item->itemnumber, $item->biblionumber);
39
        } else {
112
            } else {
40
            new_item(sprintf "Item with itemnumber=%s does not have holdingbranch defined", $item->itemnumber);
113
            new_item(sprintf "Item with itemnumber=%s and biblionumber=%s does not have holdingbranch defined", $item->itemnumber, $item->biblionumber);
41
        }
114
        }
42
    }
115
    }
43
    if ( $items->count ) { new_hint("Edit these items and set valid homebranch and/or holdingbranch")}
116
    if ( $items->count ) { new_hint("Edit these items and set valid homebranch and/or holdingbranch")}
44
}
117
}
45
118
46
{
119
sub CheckItemsAuthHeader {
47
    # No join possible, FK is missing at DB level
120
    # No join possible, FK is missing at DB level
48
    my @auth_types = Koha::Authority::Types->search->get_column('authtypecode');
121
    my @auth_types = Koha::Authority::Types->search->get_column('authtypecode');
49
    my $authorities = Koha::Authorities->search({authtypecode => { 'not in' => \@auth_types } });
122
    my $authorities = Koha::Authorities->search({authtypecode => { 'not in' => \@auth_types } });
Lines 51-212 use C4::Biblio qw( GetMarcFromKohaField ); Link Here
51
    while ( my $authority = $authorities->next ) {
124
    while ( my $authority = $authorities->next ) {
52
        new_item(sprintf "Authority with authid=%s does not have a code defined (%s)", $authority->authid, $authority->authtypecode);
125
        new_item(sprintf "Authority with authid=%s does not have a code defined (%s)", $authority->authid, $authority->authtypecode);
53
    }
126
    }
54
    if ( $authorities->count ) {new_hint("Go to 'Home › Administration › Authority types' to define them")}
127
    if ( $authorities->count ) {new_hint("Go to 'Home -> Administration -> Authority types' to define them")};
55
}
128
    };
56
129
57
{
130
    sub CheckItemsStatus {
58
    if ( C4::Context->preference('item-level_itypes') ) {
131
        if ( C4::Context->preference('item-level_itypes') ) {
59
        my $items_without_itype = Koha::Items->search( { -or => [itype => undef,itype => ''] } );
132
            my $items_without_itype = Koha::Items->search( { -or => [itype => undef,itype => ''] } );
60
        if ( $items_without_itype->count ) {
133
            if ( $items_without_itype->count ) {
61
            new_section("Items do not have itype defined");
134
                new_section("Items do not have itype defined");
62
            while ( my $item = $items_without_itype->next ) {
135
                while ( my $item = $items_without_itype->next ) {
63
                if (defined $item->biblioitem->itemtype && $item->biblioitem->itemtype ne '' ) {
136
                    if (defined $item->biblioitem->itemtype && $item->biblioitem->itemtype ne '' ) {
64
                    new_item(
137
                        new_item(
65
                        sprintf "Item with itemnumber=%s does not have a itype value, biblio's item type will be used (%s)",
138
                        sprintf "Item with itemnumber=%s and biblionumber = %s does not have a itype value, biblio's item type will be used (%s)",
66
                        $item->itemnumber, $item->biblioitem->itemtype
139
                        $item->itemnumber, $item->biblioitem->biblionumber, $item->biblioitem->itemtype
67
                    );
140
                        );
68
                } else {
141
                        } else {
69
                    new_item(
142
                        new_item(
70
                        sprintf "Item with itemnumber=%s does not have a itype value, additionally no item type defined for biblionumber=%s",
143
                        sprintf "Item with itemnumber=%s and biblionumber = %s does not have a itype value, additionally no item type defined for biblionumber=%s",
71
                        $item->itemnumber, $item->biblioitem->biblionumber
144
                        $item->itemnumber, $item->biblioitem->biblionumber, $item->biblioitem->biblionumber
72
                    );
145
                        );
73
               }
146
                    }
147
                }
148
                new_hint("The system preference item-level_itypes expects item types to be defined at item level");
74
            }
149
            }
75
            new_hint("The system preference item-level_itypes expects item types to be defined at item level");
150
        }else{
76
        }
151
            my $biblioitems_without_itemtype = Koha::Biblioitems->search( { itemtype => undef } );
77
    }
152
            if ( $biblioitems_without_itemtype->count ) {
78
    else {
153
                new_section("Biblioitems do not have itemtype defined");
79
        my $biblioitems_without_itemtype = Koha::Biblioitems->search( { itemtype => undef } );
154
                while ( my $biblioitem = $biblioitems_without_itemtype->next ) {
80
        if ( $biblioitems_without_itemtype->count ) {
155
                    new_item(
81
            new_section("Biblioitems do not have itemtype defined");
82
            while ( my $biblioitem = $biblioitems_without_itemtype->next ) {
83
                new_item(
84
                    sprintf "Biblioitem with biblioitemnumber=%s does not have a itemtype value",
156
                    sprintf "Biblioitem with biblioitemnumber=%s does not have a itemtype value",
85
                    $biblioitem->biblioitemnumber
157
                    $biblioitem->biblioitemnumber
86
                );
158
                    );
159
                }
160
                new_hint("The system preference item-level_itypes expects item types to be defined at biblio level");
87
            }
161
            }
88
            new_hint("The system preference item-level_itypes expects item types to be defined at biblio level");
89
        }
162
        }
90
    }
91
163
92
    my @itemtypes = Koha::ItemTypes->search->get_column('itemtype');
164
        my @itemtypes = Koha::ItemTypes->search->get_column('itemtype');
93
    if ( C4::Context->preference('item-level_itypes') ) {
165
        if ( C4::Context->preference('item-level_itypes') ) {
94
        my $items_with_invalid_itype = Koha::Items->search( { -and => [itype => { not_in => \@itemtypes }, itype => { '!=' => '' }] } );
166
            my $items_with_invalid_itype = Koha::Items->search( { -and => [itype => { not_in => \@itemtypes }, itype => { '!=' => '' }] } );
95
        if ( $items_with_invalid_itype->count ) {
167
            if ( $items_with_invalid_itype->count ) {
96
            new_section("Items have invalid itype defined");
168
                new_section("Items have invalid itype defined");
97
            while ( my $item = $items_with_invalid_itype->next ) {
169
                while ( my $item = $items_with_invalid_itype->next ) {
98
                new_item(
170
                    new_item(
99
                    sprintf "Item with itemnumber=%s, biblionumber=%s does not have a valid itype value (%s)",
171
                    sprintf "Item with itemnumber=%s, biblionumber=%s does not have a valid itype value (%s)",
100
                    $item->itemnumber, $item->biblionumber, $item->itype
172
                    $item->itemnumber, $item->biblionumber, $item->itype
101
                );
173
                    );
174
                }
175
                new_hint("The items must have a itype value that is defined in the item types of Koha (Home › Administration › Item types administration)");
102
            }
176
            }
103
            new_hint("The items must have a itype value that is defined in the item types of Koha (Home › Administration › Item types administration)");
177
        }else{
104
        }
178
            my $biblioitems_with_invalid_itemtype = Koha::Biblioitems->search(
105
    }
106
    else {
107
        my $biblioitems_with_invalid_itemtype = Koha::Biblioitems->search(
108
            { itemtype => { not_in => \@itemtypes } }
179
            { itemtype => { not_in => \@itemtypes } }
109
        );
180
            );
110
        if ( $biblioitems_with_invalid_itemtype->count ) {
181
            if ( $biblioitems_with_invalid_itemtype->count ) {
111
            new_section("Biblioitems do not have itemtype defined");
182
                new_section("Biblioitems do not have itemtype defined");
112
            while ( my $biblioitem = $biblioitems_with_invalid_itemtype->next ) {
183
                while ( my $biblioitem = $biblioitems_with_invalid_itemtype->next ) {
113
                new_item(
184
                    new_item(
114
                    sprintf "Biblioitem with biblioitemnumber=%s does not have a valid itemtype value",
185
                    sprintf "Biblioitem with biblioitemnumber=%s does not have a valid itemtype value",
115
                    $biblioitem->biblioitemnumber
186
                    $biblioitem->biblioitemnumber
116
                );
187
                    );
188
                }
189
                new_hint("The biblioitems must have a itemtype value that is defined in the item types of Koha (Home › Administration › Item types administration)");
117
            }
190
            }
118
            new_hint("The biblioitems must have a itemtype value that is defined in the item types of Koha (Home › Administration › Item types administration)");
119
        }
191
        }
120
    }
121
192
122
    my ( @decoding_errors, @ids_not_in_marc );
193
        my ( @decoding_errors, @ids_not_in_marc );
123
    my $biblios = Koha::Biblios->search;
194
        my $biblios = Koha::Biblios->search;
124
    my ( $biblio_tag,     $biblio_subfield )     = C4::Biblio::GetMarcFromKohaField( "biblio.biblionumber" );
195
        my ( $biblio_tag,     $biblio_subfield )     = C4::Biblio::GetMarcFromKohaField( "biblio.biblionumber" );
125
    my ( $biblioitem_tag, $biblioitem_subfield ) = C4::Biblio::GetMarcFromKohaField( "biblioitems.biblioitemnumber" );
196
        my ( $biblioitem_tag, $biblioitem_subfield ) = C4::Biblio::GetMarcFromKohaField( "biblioitems.biblioitemnumber" );
126
    while ( my $biblio = $biblios->next ) {
197
        while ( my $biblio = $biblios->next ) {
127
        my $record = eval{$biblio->metadata->record;};
198
            my $record = eval{$biblio->metadata->record;};
128
        if ($@) {
199
            if ($@) {
129
            push @decoding_errors, $@;
200
                push @decoding_errors, $@;
130
            next;
201
                next;
131
        }
202
            }
132
        my ( $biblionumber, $biblioitemnumber );
203
            my ( $biblionumber, $biblioitemnumber );
133
        if ( $biblio_tag < 10 ) {
204
            if ( $biblio_tag < 10 ) {
134
            my $biblio_control_field = $record->field($biblio_tag);
205
                my $biblio_control_field = $record->field($biblio_tag);
135
            $biblionumber = $biblio_control_field->data if $biblio_control_field;
206
                $biblionumber = $biblio_control_field->data if $biblio_control_field;
136
        } else {
207
                } else {
137
            $biblionumber = $record->subfield( $biblio_tag, $biblio_subfield );
208
                $biblionumber = $record->subfield( $biblio_tag, $biblio_subfield );
138
        }
209
            }
139
        if ( $biblioitem_tag < 10 ) {
210
            if ( $biblioitem_tag < 10 ) {
140
            my $biblioitem_control_field = $record->field($biblioitem_tag);
211
                my $biblioitem_control_field = $record->field($biblioitem_tag);
141
            $biblioitemnumber = $biblioitem_control_field->data if $biblioitem_control_field;
212
                $biblioitemnumber = $biblioitem_control_field->data if $biblioitem_control_field;
142
        } else {
213
                } else {
143
            $biblioitemnumber = $record->subfield( $biblioitem_tag, $biblioitem_subfield );
214
                $biblioitemnumber = $record->subfield( $biblioitem_tag, $biblioitem_subfield );
144
        }
215
            }
145
        if ( $biblionumber != $biblio->biblionumber ) {
216
            if ( $biblionumber != $biblio->biblionumber ) {
146
            push @ids_not_in_marc,
217
                push @ids_not_in_marc,
147
              {
218
                {
148
                biblionumber         => $biblio->biblionumber,
219
                biblionumber         => $biblio->biblionumber,
149
                biblionumber_in_marc => $biblionumber,
220
                biblionumber_in_marc => $biblionumber,
150
              };
221
                };
151
        }
222
            }
152
        if ( $biblioitemnumber != $biblio->biblioitem->biblioitemnumber ) {
223
            if ( $biblioitemnumber != $biblio->biblioitem->biblioitemnumber ) {
153
            push @ids_not_in_marc,
224
                push @ids_not_in_marc,
154
            {
225
                {
155
                biblionumber     => $biblio->biblionumber,
226
                biblionumber     => $biblio->biblionumber,
156
                biblioitemnumber => $biblio->biblioitem->biblioitemnumber,
227
                biblioitemnumber => $biblio->biblioitem->biblioitemnumber,
157
                biblioitemnumber_in_marc => $biblionumber,
228
                biblioitemnumber_in_marc => $biblionumber,
158
            };
229
                };
230
            }
159
        }
231
        }
160
    }
232
        if ( @decoding_errors ) {
161
    if ( @decoding_errors ) {
233
            new_section("Bibliographic records have invalid MARCXML");
162
        new_section("Bibliographic records have invalid MARCXML");
234
            new_item($_) for @decoding_errors;
163
        new_item($_) for @decoding_errors;
235
            new_hint("The bibliographic records must have a valid MARCXML or you will face encoding issues or wrong displays");
164
        new_hint("The bibliographic records must have a valid MARCXML or you will face encoding issues or wrong displays");
236
        }
165
    }
237
        if (@ids_not_in_marc) {
166
    if (@ids_not_in_marc) {
238
            new_section("Bibliographic records have MARCXML without biblionumber or biblioitemnumber");
167
        new_section("Bibliographic records have MARCXML without biblionumber or biblioitemnumber");
239
            for my $id (@ids_not_in_marc) {
168
        for my $id (@ids_not_in_marc) {
240
                if ( exists $id->{biblioitemnumber} ) {
169
            if ( exists $id->{biblioitemnumber} ) {
241
                    new_item(
170
                new_item(
171
                    sprintf(q{Biblionumber %s has biblioitemnumber '%s' but should be '%s' in %s$%s},
242
                    sprintf(q{Biblionumber %s has biblioitemnumber '%s' but should be '%s' in %s$%s},
172
                        $id->{biblionumber},
243
                    $id->{biblionumber},
173
                        $id->{biblioitemnumber},
244
                    $id->{biblioitemnumber},
174
                        $id->{biblioitemnumber_in_marc},
245
                    $id->{biblioitemnumber_in_marc},
175
                        $biblioitem_tag,
246
                    $biblioitem_tag,
176
                        $biblioitem_subfield,
247
                    $biblioitem_subfield,
177
                    )
248
                    )
178
                );
249
                    );
179
            }
250
                }else{
180
            else {
251
                    new_item(
181
                new_item(
182
                    sprintf(q{Biblionumber %s has '%s' in %s$%s},
252
                    sprintf(q{Biblionumber %s has '%s' in %s$%s},
183
                        $id->{biblionumber},
253
                    $id->{biblionumber},
184
                        $id->{biblionumber_in_marc},
254
                    $id->{biblionumber_in_marc},
185
                        $biblio_tag,
255
                    $biblio_tag,
186
                        $biblio_subfield,
256
                    $biblio_subfield,
187
                    )
257
                    )
188
                );
258
                    );
259
                }
189
            }
260
            }
261
            new_hint("The bibliographic records must have the biblionumber and biblioitemnumber in MARCXML");
190
        }
262
        }
191
        new_hint("The bibliographic records must have the biblionumber and biblioitemnumber in MARCXML");
192
    }
263
    }
193
}
194
264
195
{
265
    sub CheckItemsFramework {
196
    my @framework_codes = Koha::BiblioFrameworks->search()->get_column('frameworkcode');
266
        my @framework_codes = Koha::BiblioFrameworks->search()->get_column('frameworkcode');
197
    push @framework_codes,""; # The default is not stored in frameworks, we need to force it
267
        push @framework_codes,""; # The default is not stored in frameworks, we need to force it
198
268
199
    my $invalid_av_per_framework = {};
269
        my $invalid_av_per_framework = {};
200
    foreach my $frameworkcode ( @framework_codes ) {
270
        foreach my $frameworkcode ( @framework_codes ) {
201
        # We are only checking fields that are mapped to DB fields
271
            # We are only checking fields that are mapped to DB fields
202
        my $msss = Koha::MarcSubfieldStructures->search({
272
            my $msss = Koha::MarcSubfieldStructures->search({
203
            frameworkcode => $frameworkcode,
273
            frameworkcode => $frameworkcode,
204
            authorised_value => {
274
            authorised_value => {
205
                '!=' => [ -and => ( undef, '' ) ]
275
            '!=' => [ -and => ( undef, '' ) ]
206
            },
276
            },
207
            kohafield => {
277
            kohafield => {
208
                '!=' => [ -and => ( undef, '' ) ]
278
            '!=' => [ -and => ( undef, '' ) ]
209
            }
279
        }
210
        });
280
        });
211
        while ( my $mss = $msss->next ) {
281
        while ( my $mss = $msss->next ) {
212
            my $kohafield = $mss->kohafield;
282
            my $kohafield = $mss->kohafield;
Lines 214-279 use C4::Biblio qw( GetMarcFromKohaField ); Link Here
214
            next if grep {$_ eq $av} qw( branches itemtypes cn_source ); # internal categories
284
            next if grep {$_ eq $av} qw( branches itemtypes cn_source ); # internal categories
215
285
216
            my $avs = Koha::AuthorisedValues->search_by_koha_field(
286
            my $avs = Koha::AuthorisedValues->search_by_koha_field(
217
                {
287
            {
218
                    frameworkcode => $frameworkcode,
288
            frameworkcode => $frameworkcode,
219
                    kohafield     => $kohafield,
289
            kohafield     => $kohafield,
220
                }
290
        }
221
            );
291
        );
222
            my $tmp_kohafield = $kohafield;
292
        my $tmp_kohafield = $kohafield;
223
            if ( $tmp_kohafield =~ /^biblioitems/ ) {
293
        if ( $tmp_kohafield =~ /^biblioitems/ ) {
224
                $tmp_kohafield =~ s|biblioitems|biblioitem|;
294
            $tmp_kohafield =~ s|biblioitems|biblioitem|;
225
            } else {
295
            } else {
226
                $tmp_kohafield =~ s|items|me|;
296
            $tmp_kohafield =~ s|items|me|;
227
            }
297
        }
228
            # replace items.attr with me.attr
298
        # replace items.attr with me.attr
229
299
230
            # We are only checking biblios with items
300
        # We are only checking biblios with items
231
            my $items = Koha::Items->search(
301
        my $items = Koha::Items->search(
232
                {
302
        {
233
                    $tmp_kohafield =>
303
        $tmp_kohafield =>
234
                      {
304
        {
235
                          -not_in => [ $avs->get_column('authorised_value'), '' ],
305
        -not_in => [ $avs->get_column('authorised_value'), '' ],
236
                          '!='    => undef,
306
        '!='    => undef,
237
                      },
307
        },
238
                    'biblio.frameworkcode' => $frameworkcode
308
        'biblio.frameworkcode' => $frameworkcode
239
                },
309
        },
240
                { join => [ 'biblioitem', 'biblio' ] }
310
        { join => [ 'biblioitem', 'biblio' ] }
241
            );
311
        );
242
            if ( $items->count ) {
312
        if ( $items->count ) {
243
                $invalid_av_per_framework->{ $frameworkcode }->{$av} =
313
            $invalid_av_per_framework->{ $frameworkcode }->{$av} =
244
                  { items => $items, kohafield => $kohafield };
314
            { items => $items, kohafield => $kohafield };
245
            }
246
        }
315
        }
247
    }
316
    }
248
    if (%$invalid_av_per_framework) {
317
}
249
        new_section('Wrong values linked to authorised values');
318
if (%$invalid_av_per_framework) {
250
        for my $frameworkcode ( keys %$invalid_av_per_framework ) {
319
    new_section('Wrong values linked to authorised values');
251
            while ( my ( $av_category, $v ) = each %{$invalid_av_per_framework->{$frameworkcode}} ) {
320
    for my $frameworkcode ( keys %$invalid_av_per_framework ) {
252
                my $items     = $v->{items};
321
        while ( my ( $av_category, $v ) = each %{$invalid_av_per_framework->{$frameworkcode}} ) {
253
                my $kohafield = $v->{kohafield};
322
            my $items     = $v->{items};
254
                my ( $table, $column ) = split '\.', $kohafield;
323
            my $kohafield = $v->{kohafield};
255
                my $output;
324
            my ( $table, $column ) = split '\.', $kohafield;
256
                while ( my $i = $items->next ) {
325
            my $output;
257
                    my $value = $table eq 'items'
326
            while ( my $i = $items->next ) {
258
                        ? $i->$column
327
                my $value = $table eq 'items'
259
                        : $table eq 'biblio'
328
                ? $i->$column
260
                        ? $i->biblio->$column
329
                : $table eq 'biblio'
261
                        : $i->biblioitem->$column;
330
                ? $i->biblio->$column
262
                    $output .= " {" . $i->itemnumber . " => " . $value . "}\n";
331
                : $i->biblioitem->$column;
263
                }
332
                $output .= " {" . $i->itemnumber . " and " . $i->biblioitem->biblionumber. " => " . $value . "}\n";
264
                new_item(
265
                    sprintf(
266
                        "The Framework *%s* is using the authorised value's category *%s*, "
267
                        . "but the following %s do not have a value defined ({itemnumber => value }):\n%s",
268
                        $frameworkcode, $av_category, $kohafield, $output
269
                    )
270
                );
271
            }
333
            }
334
            new_item(
335
            sprintf(
336
            "The Framework *%s* is using the authorised value's category *%s*, "
337
            . "but the following %s do not have a value defined ({itemnumber and biblionumber => value }):\n%s",
338
            $frameworkcode, $av_category, $kohafield, $output
339
            )
340
            );
272
        }
341
        }
273
    }
342
    }
274
}
343
}
344
}
275
345
276
{
346
sub CheckItemsTitle {
277
    my $biblios = Koha::Biblios->search({
347
    my $biblios = Koha::Biblios->search({
278
        -or => [
348
        -or => [
279
            title => '',
349
            title => '',
Lines 292-298 use C4::Biblio qw( GetMarcFromKohaField ); Link Here
292
    }
362
    }
293
}
363
}
294
364
295
{
365
sub CheckAgeForCategory {
296
    my $aging_patrons = Koha::Patrons->search(
366
    my $aging_patrons = Koha::Patrons->search(
297
        {
367
        {
298
            -not => {
368
            -not => {
Lines 464-489 sub new_hint { Link Here
464
    say "=> $name";
534
    say "=> $name";
465
}
535
}
466
536
467
=head1 NAME
468
469
search_for_data_inconsistencies.pl
470
471
=head1 SYNOPSIS
537
=head1 SYNOPSIS
472
538
473
    perl search_for_data_inconsistencies.pl
539
search_for_data_inconsistencies.pl [options]
474
540
475
=head1 DESCRIPTION
541
=head2 DESCRIPTION
476
542
477
Catch data inconsistencies in Koha database
543
Catch data inconsistencies in Koha database:
478
544
479
* Items with undefined homebranch and/or holdingbranch
545
    * Items with undefined homebranch and/or holdingbranch
480
* Authorities with undefined authtypecodes/authority types
546
    * Authorities with undefined authtypecodes/authority types
481
* Item types:
547
    * Item types:
482
  * if item types are defined at item level (item-level_itypes=specific item),
548
        * if item types are defined at item level (item-level_itypes=specific item),
483
    then items.itype must be set else biblioitems.itemtype must be set
549
        then items.itype must be set else biblioitems.itemtype must be set
484
  * Item types defined in items or biblioitems must be defined in the itemtypes table
550
        * Item types defined in items or biblioitems must be defined in the itemtypes table
485
* Invalid MARCXML in bibliographic records
551
    * Bibliographic records without a title
486
* Patrons with invalid category types due to lower and upper age limits
552
    * Invalid MARCXML in bibliographic records
553
    * Patrons with invalid category types due to lower and upper age limits
487
* Any date fields in the database (timestamp, datetime, date) set to 0000-00-00
554
* Any date fields in the database (timestamp, datetime, date) set to 0000-00-00
488
555
489
=cut
556
=head2 OPTIONS
557
558
  --check-branch      Check for items without home or holding library
559
  --check-auth        Check for authority records with invalid authority type
560
  --check-status      Check for bibliographic records and items without an item type or with an invalid item type
561
  --check-framework   Check for invalid values in fields where the framework limits to an authorized value category
562
  --check-title       Check for bibliographic records without a title
563
  --check-age         Check for patrons with invalid age for category
564
  --skip-branch       Skip checking for items without home or holding library
565
  --skip-auth         Skip checking for authority records with invalid authority type
566
  --skip-status       Skip checking for bibliographic records and items without an item type or with an invalid item type
567
  --skip-framework    Skip checking for invalid values in fields where the framework limits to an authorized value category
568
  --skip-title        Skip checking for bibliographic records without a title
569
  --skip-age          Skip checking for patrons with invalid age for category
570
  --help              Print usage information
571
572
Note: If no options are provided, all tests will be run.
573
574
=cut
490
- 

Return to bug 36027