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

(-)a/Koha/REST/Plugin/Query.pm (-89 / +87 lines)
Lines 19-26 use Modern::Perl; Link Here
19
19
20
use Mojo::Base 'Mojolicious::Plugin';
20
use Mojo::Base 'Mojolicious::Plugin';
21
use List::MoreUtils qw( any );
21
use List::MoreUtils qw( any );
22
use Scalar::Util qw( reftype );
22
use Scalar::Util    qw( reftype );
23
use JSON qw( decode_json );
23
use JSON            qw( decode_json );
24
24
25
use Koha::Exceptions;
25
use Koha::Exceptions;
26
use Koha::Exceptions::REST;
26
use Koha::Exceptions::REST;
Lines 58-74 Generates the DBIC query from the query parameters. Link Here
58
            my $filtered_params;
58
            my $filtered_params;
59
            my $path_params;
59
            my $path_params;
60
60
61
            my $reserved_words = _reserved_words();
61
            my $reserved_words    = _reserved_words();
62
            my @query_param_names = keys %{$c->req->params->to_hash};
62
            my @query_param_names = keys %{ $c->req->params->to_hash };
63
63
64
            foreach my $param ( keys %{$params} ) {
64
            foreach my $param ( keys %{$params} ) {
65
                if ( grep { $param eq $_ } @{$reserved_words} ) {
65
                if ( grep { $param eq $_ } @{$reserved_words} ) {
66
                    $reserved_params->{$param} = $params->{$param};
66
                    $reserved_params->{$param} = $params->{$param};
67
                }
67
                } elsif ( grep { $param eq $_ } @query_param_names ) {
68
                elsif ( grep { $param eq $_ } @query_param_names ) {
69
                    $filtered_params->{$param} = $params->{$param};
68
                    $filtered_params->{$param} = $params->{$param};
70
                }
69
                } else {
71
                else {
72
                    $path_params->{$param} = $params->{$param};
70
                    $path_params->{$param} = $params->{$param};
73
                }
71
                }
74
            }
72
            }
Lines 97-107 Generates the DBIC order_by attributes based on I<$params>, and merges into I<$a Link Here
97
            );
95
            );
98
            my @order_by_params;
96
            my @order_by_params;
99
97
100
            foreach my $order_by_style ( @order_by_styles ) {
98
            foreach my $order_by_style (@order_by_styles) {
101
                if ( defined $args->{params}->{$order_by_style} and ref($args->{params}->{$order_by_style}) eq 'ARRAY' )  {
99
                if ( defined $args->{params}->{$order_by_style}
102
                    push( @order_by_params, @{$args->{params}->{$order_by_style} });
100
                    and ref( $args->{params}->{$order_by_style} ) eq 'ARRAY' )
103
                }
101
                {
104
                else {
102
                    push( @order_by_params, @{ $args->{params}->{$order_by_style} } );
103
                } else {
105
                    push @order_by_params, $args->{params}->{$order_by_style}
104
                    push @order_by_params, $args->{params}->{$order_by_style}
106
                        if defined $args->{params}->{$order_by_style};
105
                        if defined $args->{params}->{$order_by_style};
107
                }
106
                }
Lines 109-126 Generates the DBIC order_by attributes based on I<$params>, and merges into I<$a Link Here
109
108
110
            my @THE_order_by;
109
            my @THE_order_by;
111
110
112
            foreach my $order_by_param ( @order_by_params ) {
111
            foreach my $order_by_param (@order_by_params) {
113
                my $order_by;
112
                my $order_by;
114
                $order_by = [ split(/,/, $order_by_param) ]
113
                $order_by = [ split( /,/, $order_by_param ) ]
115
                    if ( !reftype($order_by_param) && index(',',$order_by_param) == -1);
114
                    if ( !reftype($order_by_param) && index( ',', $order_by_param ) == -1 );
116
115
117
                if ($order_by) {
116
                if ($order_by) {
118
                    if ( reftype($order_by) and reftype($order_by) eq 'ARRAY' ) {
117
                    if ( reftype($order_by) and reftype($order_by) eq 'ARRAY' ) {
119
                        my @order_by = map { _build_order_atom({ string => $_, result_set => $result_set }) } @{ $order_by };
118
                        my @order_by =
120
                        push( @THE_order_by, @order_by);
119
                            map { _build_order_atom( { string => $_, result_set => $result_set } ) } @{$order_by};
121
                    }
120
                        push( @THE_order_by, @order_by );
122
                    else {
121
                    } else {
123
                        push @THE_order_by, _build_order_atom({ string => $order_by, result_set => $result_set });
122
                        push @THE_order_by, _build_order_atom( { string => $order_by, result_set => $result_set } );
124
                    }
123
                    }
125
                }
124
                }
126
            }
125
            }
Lines 145-160 Generates the DBIC prefetch attribute based on embedded relations, and merges in Link Here
145
            my ( $c, $args ) = @_;
144
            my ( $c, $args ) = @_;
146
            my $attributes = $args->{attributes};
145
            my $attributes = $args->{attributes};
147
            my $result_set = $args->{result_set};
146
            my $result_set = $args->{result_set};
148
            my $embed = $c->stash('koha.embed');
147
            my $embed      = $c->stash('koha.embed');
149
            return unless defined $embed;
148
            return unless defined $embed;
150
149
151
            my @prefetches;
150
            my @prefetches;
152
            foreach my $key (sort keys(%{$embed})) {
151
            foreach my $key ( sort keys( %{$embed} ) ) {
153
                my $parsed = _parse_prefetch($key, $embed, $result_set);
152
                my $parsed = _parse_prefetch( $key, $embed, $result_set );
154
                push @prefetches, $parsed if defined $parsed;
153
                push @prefetches, $parsed if defined $parsed;
155
            }
154
            }
156
155
157
            if(scalar(@prefetches)) {
156
            if ( scalar(@prefetches) ) {
158
                $attributes->{prefetch} = \@prefetches;
157
                $attributes->{prefetch} = \@prefetches;
159
            }
158
            }
160
        }
159
        }
Lines 195-218 is raised. Link Here
195
            my $match = $reserved_params->{_match} // 'contains';
194
            my $match = $reserved_params->{_match} // 'contains';
196
195
197
            foreach my $param ( keys %{$filtered_params} ) {
196
            foreach my $param ( keys %{$filtered_params} ) {
198
                if ( $match eq 'exact' || $filtered_params->{$param} =~ m[^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}]) {
197
                if ( $match eq 'exact' || $filtered_params->{$param} =~ m[^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}] ) {
199
                    $params->{$param} = $filtered_params->{$param};
198
                    $params->{$param} = $filtered_params->{$param};
200
                }
199
                } elsif ( $match eq 'contains' ) {
201
                elsif ( $match eq 'contains' ) {
202
                    $params->{$param} =
200
                    $params->{$param} =
203
                      { like => '%' . $filtered_params->{$param} . '%' };
201
                        { like => '%' . $filtered_params->{$param} . '%' };
204
                }
202
                } elsif ( $match eq 'starts_with' ) {
205
                elsif ( $match eq 'starts_with' ) {
206
                    $params->{$param} = { like => $filtered_params->{$param} . '%' };
203
                    $params->{$param} = { like => $filtered_params->{$param} . '%' };
207
                }
204
                } elsif ( $match eq 'ends_with' ) {
208
                elsif ( $match eq 'ends_with' ) {
209
                    $params->{$param} = { like => '%' . $filtered_params->{$param} };
205
                    $params->{$param} = { like => '%' . $filtered_params->{$param} };
210
                }
206
                } else {
211
                else {
207
212
                    # We should never reach here, because the OpenAPI plugin should
208
                    # We should never reach here, because the OpenAPI plugin should
213
                    # prevent invalid params to be passed
209
                    # prevent invalid params to be passed
214
                    Koha::Exceptions::WrongParameter->throw(
210
                    Koha::Exceptions::WrongParameter->throw("Invalid value for _match param ($match)");
215
                        "Invalid value for _match param ($match)");
216
                }
211
                }
217
            }
212
            }
218
213
Lines 235-244 Merges parameters from $q_params into $filtered_params. Link Here
235
230
236
            $q_params = decode_json($q_params) unless reftype $q_params;
231
            $q_params = decode_json($q_params) unless reftype $q_params;
237
232
238
            my $params = _parse_dbic_query($q_params, $result_set);
233
            my $params = _parse_dbic_query( $q_params, $result_set );
239
234
240
            return $params unless scalar(keys %{$filtered_params});
235
            return $params unless scalar( keys %{$filtered_params} );
241
            return {'-and' => [$params, $filtered_params ]};
236
            return { '-and' => [ $params, $filtered_params ] };
242
        }
237
        }
243
    );
238
    );
244
239
Lines 264-286 Unwraps and stashes the x-koha-embed headers for use later query construction Link Here
264
                next unless $param->{name} eq 'x-koha-embed';
259
                next unless $param->{name} eq 'x-koha-embed';
265
                $embed_spec = $param->{items}->{enum};
260
                $embed_spec = $param->{items}->{enum};
266
            }
261
            }
267
            Koha::Exceptions::BadParameter->throw(
262
            Koha::Exceptions::BadParameter->throw("Embedding objects is not allowed on this endpoint.")
268
                "Embedding objects is not allowed on this endpoint.")
263
                unless defined($embed_spec);
269
              unless defined($embed_spec);
270
264
271
            if ($embed_header) {
265
            if ($embed_header) {
272
                my $THE_embed = {};
266
                my $THE_embed = {};
273
                foreach my $embed_req ( split /\s*,\s*/, $embed_header ) {
267
                foreach my $embed_req ( split /\s*,\s*/, $embed_header ) {
274
                    if ( $embed_req eq '+strings' ) {    # special case
268
                    if ( $embed_req eq '+strings' ) {    # special case
275
                        $c->stash( 'koha.strings' => 1 );
269
                        $c->stash( 'koha.strings' => 1 );
276
                    }
270
                    } else {
277
                    else {
278
                        _merge_embed( _parse_embed($embed_req), $THE_embed );
271
                        _merge_embed( _parse_embed($embed_req), $THE_embed );
279
                    }
272
                    }
280
                }
273
                }
281
274
282
                $c->stash( 'koha.embed' => $THE_embed )
275
                $c->stash( 'koha.embed' => $THE_embed )
283
                  if $THE_embed;
276
                    if $THE_embed;
284
            }
277
            }
285
278
286
            return $c;
279
            return $c;
Lines 308-314 reference: https://metacpan.org/changes/distribution/JSON-Validator#L14 Link Here
308
    $app->helper(
301
    $app->helper(
309
        'stash_overrides' => sub {
302
        'stash_overrides' => sub {
310
303
311
            my ( $c ) = @_;
304
            my ($c) = @_;
312
305
313
            my $override_header = $c->req->headers->header('x-koha-override') || q{};
306
            my $override_header = $c->req->headers->header('x-koha-override') || q{};
314
307
Lines 349-375 according to the following rules: Link Here
349
=cut
342
=cut
350
343
351
sub _build_order_atom {
344
sub _build_order_atom {
352
    my ( $args )   = @_;
345
    my ($args)     = @_;
353
    my $string     = $args->{string};
346
    my $string     = $args->{string};
354
    my $result_set = $args->{result_set};
347
    my $result_set = $args->{result_set};
355
348
356
    my $param = $string;
349
    my $param = $string;
357
    $param =~ s/^(\+|\-|\s)//;
350
    $param =~ s/^(\+|\-|\s)//;
358
    if ( $result_set ) {
351
    if ($result_set) {
359
        my $model_param = _from_api_param($param, $result_set);
352
        my $model_param = _from_api_param( $param, $result_set );
360
        $param = $model_param if defined $model_param;
353
        $param = $model_param if defined $model_param;
361
    }
354
    }
362
355
363
    if ( $string =~ m/^\+/ or
356
    if (   $string =~ m/^\+/
364
         $string =~ m/^\s/ ) {
357
        or $string =~ m/^\s/ )
358
    {
365
        # asc order operator present
359
        # asc order operator present
366
        return { -asc => $param };
360
        return { -asc => $param };
367
    }
361
    } elsif ( $string =~ m/^\-/ ) {
368
    elsif ( $string =~ m/^\-/ ) {
362
369
        # desc order operator present
363
        # desc order operator present
370
        return { -desc => $param };
364
        return { -desc => $param };
371
    }
365
    } else {
372
    else {
366
373
        # no order operator present
367
        # no order operator present
374
        return $param;
368
        return $param;
375
    }
369
    }
Lines 390-408 sub _parse_embed { Link Here
390
    my $result;
384
    my $result;
391
    my ( $curr, $next ) = split /\s*\.\s*/, $string, 2;
385
    my ( $curr, $next ) = split /\s*\.\s*/, $string, 2;
392
386
393
    if ( $next ) {
387
    if ($next) {
394
        $result->{$curr} = { children => _parse_embed( $next ) };
388
        $result->{$curr} = { children => _parse_embed($next) };
395
    }
389
    } else {
396
    else {
397
        if ( $curr =~ m/^(?<relation>.*)[\+|:]count/ ) {
390
        if ( $curr =~ m/^(?<relation>.*)[\+|:]count/ ) {
398
            my $key = $+{relation} . "_count";
391
            my $key = $+{relation} . "_count";
399
            $result->{$key} = { is_count => 1 };
392
            $result->{$key} = { is_count => 1 };
400
        }
393
        } elsif ( $curr =~ m/^(?<relation>.*)\+strings/ ) {
401
        elsif ( $curr =~ m/^(?<relation>.*)\+strings/ ) {
402
            my $key = $+{relation};
394
            my $key = $+{relation};
403
            $result->{$key} = { strings => 1 };
395
            $result->{$key} = { strings => 1 };
404
        }
396
        } else {
405
        else {
406
            $result->{$curr} = {};
397
            $result->{$curr} = {};
407
        }
398
        }
408
    }
399
    }
Lines 421-440 Merges the hash referenced by I<$parsed_embed> into I<$global_embed>. Link Here
421
sub _merge_embed {
412
sub _merge_embed {
422
    my ( $structure, $embed ) = @_;
413
    my ( $structure, $embed ) = @_;
423
414
424
    my ($root) = keys %{ $structure };
415
    my ($root) = keys %{$structure};
416
417
    if ( any { $root eq $_ } keys %{$embed} ) {
425
418
426
    if ( any { $root eq $_ } keys %{ $embed } ) {
427
        # Recurse
419
        # Recurse
428
        _merge_embed( $structure->{$root}, $embed->{$root} );
420
        _merge_embed( $structure->{$root}, $embed->{$root} );
429
    }
421
    } else {
430
    else {
422
431
        # Embed
423
        # Embed
432
        $embed->{$root} = $structure->{$root};
424
        $embed->{$root} = $structure->{$root};
433
    }
425
    }
434
}
426
}
435
427
436
sub _parse_prefetch {
428
sub _parse_prefetch {
437
    my ( $key, $embed, $result_set) = @_;
429
    my ( $key, $embed, $result_set ) = @_;
438
430
439
    my $pref_key = $key;
431
    my $pref_key = $key;
440
    $pref_key =~ s/_count$// if $embed->{$key}->{is_count};
432
    $pref_key =~ s/_count$// if $embed->{$key}->{is_count};
Lines 444-469 sub _parse_prefetch { Link Here
444
    return $pref_key unless defined $embed->{$key}->{children} && defined $ko_class;
436
    return $pref_key unless defined $embed->{$key}->{children} && defined $ko_class;
445
437
446
    my @prefetches;
438
    my @prefetches;
447
    foreach my $child (sort keys(%{$embed->{$key}->{children}})) {
439
    foreach my $child ( sort keys( %{ $embed->{$key}->{children} } ) ) {
448
        my $parsed = _parse_prefetch($child, $embed->{$key}->{children}, $ko_class->new);
440
        my $parsed = _parse_prefetch( $child, $embed->{$key}->{children}, $ko_class->new );
449
        push @prefetches, $parsed if defined $parsed;
441
        push @prefetches, $parsed if defined $parsed;
450
    }
442
    }
451
443
452
    return $pref_key unless scalar(@prefetches);
444
    return $pref_key unless scalar(@prefetches);
453
445
454
    return {$pref_key => $prefetches[0]} if scalar(@prefetches) eq 1;
446
    return { $pref_key => $prefetches[0] } if scalar(@prefetches) eq 1;
455
447
456
    return {$pref_key => \@prefetches};
448
    return { $pref_key => \@prefetches };
457
}
449
}
458
450
459
sub _from_api_param {
451
sub _from_api_param {
460
    my ($key, $result_set) = @_;
452
    my ( $key, $result_set ) = @_;
461
453
462
    if($key =~ /\./) {
454
    if ( $key =~ /\./ ) {
463
455
464
        my ($curr, $next) = split /\s*\.\s*/, $key, 2;
456
        my ( $curr, $next ) = split /\s*\.\s*/, $key, 2;
465
457
466
        return $curr.'.'._from_api_param($next, $result_set) if $curr eq 'me';
458
        return $curr . '.' . _from_api_param( $next, $result_set ) if $curr eq 'me';
467
459
468
        my $ko_class = $result_set->prefetch_whitelist->{$curr};
460
        my $ko_class = $result_set->prefetch_whitelist->{$curr};
469
461
Lines 472-481 sub _from_api_param { Link Here
472
464
473
        $result_set = $ko_class->new;
465
        $result_set = $ko_class->new;
474
466
475
        if ($next =~ /\./) {
467
        if ( $next =~ /\./ ) {
476
            return _from_api_param($next, $result_set);
468
            return _from_api_param( $next, $result_set );
477
        } else {
469
        } else {
478
            return $curr.'.'.($result_set->from_api_mapping && defined $result_set->from_api_mapping->{$next} ? $result_set->from_api_mapping->{$next}:$next);
470
            return
471
                $curr . '.'
472
                . (
473
                  $result_set->from_api_mapping && defined $result_set->from_api_mapping->{$next}
474
                ? $result_set->from_api_mapping->{$next}
475
                : $next
476
                );
479
        }
477
        }
480
    } else {
478
    } else {
481
        return defined $result_set->from_api_mapping->{$key} ? $result_set->from_api_mapping->{$key} : $key;
479
        return defined $result_set->from_api_mapping->{$key} ? $result_set->from_api_mapping->{$key} : $key;
Lines 483-503 sub _from_api_param { Link Here
483
}
481
}
484
482
485
sub _parse_dbic_query {
483
sub _parse_dbic_query {
486
    my ($q_params, $result_set) = @_;
484
    my ( $q_params, $result_set ) = @_;
487
485
488
    if(reftype($q_params) && reftype($q_params) eq 'HASH') {
486
    if ( reftype($q_params) && reftype($q_params) eq 'HASH' ) {
489
        my $parsed_hash;
487
        my $parsed_hash;
490
        foreach my $key (keys %{$q_params}) {
488
        foreach my $key ( keys %{$q_params} ) {
491
            if($key =~ /-?(not_?)?bool/i ) {
489
            if ( $key =~ /-?(not_?)?bool/i ) {
492
                $parsed_hash->{$key} = _from_api_param($q_params->{$key}, $result_set);
490
                $parsed_hash->{$key} = _from_api_param( $q_params->{$key}, $result_set );
493
                next;
491
                next;
494
            }
492
            }
495
            my $k = _from_api_param($key, $result_set);
493
            my $k = _from_api_param( $key, $result_set );
496
            $parsed_hash->{$k} = _parse_dbic_query($q_params->{$key}, $result_set);
494
            $parsed_hash->{$k} = _parse_dbic_query( $q_params->{$key}, $result_set );
497
        }
495
        }
498
        return $parsed_hash;
496
        return $parsed_hash;
499
    } elsif (reftype($q_params) && reftype($q_params) eq 'ARRAY') {
497
    } elsif ( reftype($q_params) && reftype($q_params) eq 'ARRAY' ) {
500
        my @mapped = map{ _parse_dbic_query($_, $result_set) } @$q_params;
498
        my @mapped = map { _parse_dbic_query( $_, $result_set ) } @$q_params;
501
        return \@mapped;
499
        return \@mapped;
502
    } else {
500
    } else {
503
        return $q_params;
501
        return $q_params;
(-)a/t/db_dependent/Koha/Object.t (-219 / +235 lines)
Lines 23-29 use Test::Warn; Link Here
23
23
24
use C4::Context;
24
use C4::Context;
25
use C4::Circulation qw( AddIssue );
25
use C4::Circulation qw( AddIssue );
26
use C4::Biblio qw( AddBiblio );
26
use C4::Biblio      qw( AddBiblio );
27
27
28
use Koha::Database;
28
use Koha::Database;
29
29
Lines 56-67 subtest 'is_changed / make_column_dirty' => sub { Link Here
56
56
57
    $schema->storage->txn_begin;
57
    $schema->storage->txn_begin;
58
58
59
    my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
59
    my $categorycode = $builder->build( { source => 'Category' } )->{categorycode};
60
    my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
60
    my $branchcode   = $builder->build( { source => 'Branch' } )->{branchcode};
61
61
62
    my $object = Koha::Patron->new();
62
    my $object = Koha::Patron->new();
63
    $object->categorycode( $categorycode );
63
    $object->categorycode($categorycode);
64
    $object->branchcode( $branchcode );
64
    $object->branchcode($branchcode);
65
    $object->surname("Test Surname");
65
    $object->surname("Test Surname");
66
    $object->store->discard_changes;
66
    $object->store->discard_changes;
67
    is( $object->is_changed(), 0, "Object is unchanged" );
67
    is( $object->is_changed(), 0, "Object is unchanged" );
Lines 73-87 subtest 'is_changed / make_column_dirty' => sub { Link Here
73
    $object->store();
73
    $object->store();
74
    is( $object->is_changed(), 0, "Object no longer marked as changed after being stored" );
74
    is( $object->is_changed(), 0, "Object no longer marked as changed after being stored" );
75
75
76
    $object->set({ firstname => 'Test Firstname' });
76
    $object->set( { firstname => 'Test Firstname' } );
77
    is( $object->is_changed(), 1, "Object is changed after Set" );
77
    is( $object->is_changed(), 1, "Object is changed after Set" );
78
    $object->store();
78
    $object->store();
79
    is( $object->is_changed(), 0, "Object no longer marked as changed after being stored" );
79
    is( $object->is_changed(), 0, "Object no longer marked as changed after being stored" );
80
80
81
    # Test make_column_dirty
81
    # Test make_column_dirty
82
    is( $object->make_column_dirty('firstname'), '', 'make_column_dirty returns empty string on success' );
82
    is( $object->make_column_dirty('firstname'), '', 'make_column_dirty returns empty string on success' );
83
    is( $object->make_column_dirty('firstname'), 1, 'make_column_dirty returns 1 if already dirty' );
83
    is( $object->make_column_dirty('firstname'), 1,  'make_column_dirty returns 1 if already dirty' );
84
    is( $object->is_changed, 1, "Object is changed after make dirty" );
84
    is( $object->is_changed,                     1,  "Object is changed after make dirty" );
85
    $object->store;
85
    $object->store;
86
    is( $object->is_changed, 0, "Store clears dirty mark" );
86
    is( $object->is_changed, 0, "Store clears dirty mark" );
87
    $object->make_column_dirty('firstname');
87
    $object->make_column_dirty('firstname');
Lines 96-108 subtest 'in_storage' => sub { Link Here
96
96
97
    $schema->storage->txn_begin;
97
    $schema->storage->txn_begin;
98
98
99
    my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
99
    my $categorycode = $builder->build( { source => 'Category' } )->{categorycode};
100
    my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
100
    my $branchcode   = $builder->build( { source => 'Branch' } )->{branchcode};
101
101
102
    my $object = Koha::Patron->new();
102
    my $object = Koha::Patron->new();
103
    is( $object->in_storage, 0, "Object is not in storage" );
103
    is( $object->in_storage, 0, "Object is not in storage" );
104
    $object->categorycode( $categorycode );
104
    $object->categorycode($categorycode);
105
    $object->branchcode( $branchcode );
105
    $object->branchcode($branchcode);
106
    $object->surname("Test Surname");
106
    $object->surname("Test Surname");
107
    $object->store();
107
    $object->store();
108
    is( $object->in_storage, 1, "Object is now stored" );
108
    is( $object->in_storage, 1, "Object is now stored" );
Lines 110-121 subtest 'in_storage' => sub { Link Here
110
    is( $object->in_storage, 1 );
110
    is( $object->in_storage, 1 );
111
111
112
    my $borrowernumber = $object->borrowernumber;
112
    my $borrowernumber = $object->borrowernumber;
113
    my $patron = $schema->resultset('Borrower')->find( $borrowernumber );
113
    my $patron         = $schema->resultset('Borrower')->find($borrowernumber);
114
    is( $patron->surname(), "Test Surname", "Object found in database" );
114
    is( $patron->surname(), "Test Surname", "Object found in database" );
115
115
116
    $object->delete();
116
    $object->delete();
117
    $patron = $schema->resultset('Borrower')->find( $borrowernumber );
117
    $patron = $schema->resultset('Borrower')->find($borrowernumber);
118
    ok( ! $patron, "Object no longer found in database" );
118
    ok( !$patron, "Object no longer found in database" );
119
    is( $object->in_storage, 0, "Object is not in storage" );
119
    is( $object->in_storage, 0, "Object is not in storage" );
120
120
121
    $schema->storage->txn_rollback;
121
    $schema->storage->txn_rollback;
Lines 126-135 subtest 'id' => sub { Link Here
126
126
127
    $schema->storage->txn_begin;
127
    $schema->storage->txn_begin;
128
128
129
    my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
129
    my $categorycode = $builder->build( { source => 'Category' } )->{categorycode};
130
    my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
130
    my $branchcode   = $builder->build( { source => 'Branch' } )->{branchcode};
131
131
132
    my $patron = Koha::Patron->new({categorycode => $categorycode, branchcode => $branchcode })->store;
132
    my $patron = Koha::Patron->new( { categorycode => $categorycode, branchcode => $branchcode } )->store;
133
    is( $patron->id, $patron->borrowernumber );
133
    is( $patron->id, $patron->borrowernumber );
134
134
135
    $schema->storage->txn_rollback;
135
    $schema->storage->txn_rollback;
Lines 140-150 subtest 'get_column' => sub { Link Here
140
140
141
    $schema->storage->txn_begin;
141
    $schema->storage->txn_begin;
142
142
143
    my $categorycode = $builder->build({ source => 'Category' })->{categorycode};
143
    my $categorycode = $builder->build( { source => 'Category' } )->{categorycode};
144
    my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
144
    my $branchcode   = $builder->build( { source => 'Branch' } )->{branchcode};
145
145
146
    my $patron = Koha::Patron->new({categorycode => $categorycode, branchcode => $branchcode })->store;
146
    my $patron = Koha::Patron->new( { categorycode => $categorycode, branchcode => $branchcode } )->store;
147
    is( $patron->get_column('borrowernumber'), $patron->borrowernumber, 'get_column should retrieve the correct value' );
147
    is(
148
        $patron->get_column('borrowernumber'), $patron->borrowernumber,
149
        'get_column should retrieve the correct value'
150
    );
148
151
149
    $schema->storage->txn_rollback;
152
    $schema->storage->txn_rollback;
150
};
153
};
Lines 173-192 subtest 'TO_JSON tests' => sub { Link Here
173
176
174
    $schema->storage->txn_begin;
177
    $schema->storage->txn_begin;
175
178
176
    my $dt = dt_from_string();
179
    my $dt             = dt_from_string();
177
    my $borrowernumber = $builder->build(
180
    my $borrowernumber = $builder->build(
178
        { source => 'Borrower',
181
        {
179
          value => { lost => 1,
182
            source => 'Borrower',
180
                     sms_provider_id => undef,
183
            value  => {
181
                     gonenoaddress => 0,
184
                lost            => 1,
182
                     updated_on => $dt,
185
                sms_provider_id => undef,
183
                     lastseen   => $dt, } })->{borrowernumber};
186
                gonenoaddress   => 0,
184
187
                updated_on      => $dt,
185
    my $patron = Koha::Patrons->find($borrowernumber);
188
                lastseen        => $dt,
186
    my $lost = $patron->TO_JSON()->{lost};
189
            }
190
        }
191
    )->{borrowernumber};
192
193
    my $patron        = Koha::Patrons->find($borrowernumber);
194
    my $lost          = $patron->TO_JSON()->{lost};
187
    my $gonenoaddress = $patron->TO_JSON->{gonenoaddress};
195
    my $gonenoaddress = $patron->TO_JSON->{gonenoaddress};
188
    my $updated_on = $patron->TO_JSON->{updated_on};
196
    my $updated_on    = $patron->TO_JSON->{updated_on};
189
    my $lastseen = $patron->TO_JSON->{lastseen};
197
    my $lastseen      = $patron->TO_JSON->{lastseen};
190
198
191
    ok( $lost->isa('JSON::PP::Boolean'), 'Boolean attribute type is correct' );
199
    ok( $lost->isa('JSON::PP::Boolean'), 'Boolean attribute type is correct' );
192
    is( $lost, 1, 'Boolean attribute value is correct (true)' );
200
    is( $lost, 1, 'Boolean attribute value is correct (true)' );
Lines 196-202 subtest 'TO_JSON tests' => sub { Link Here
196
204
197
    is( $patron->TO_JSON->{sms_provider_id}, undef, 'Undef values should not be casted to 0' );
205
    is( $patron->TO_JSON->{sms_provider_id}, undef, 'Undef values should not be casted to 0' );
198
206
199
    ok( !isvstring($patron->borrowernumber), 'Integer values are not coded as strings' );
207
    ok( !isvstring( $patron->borrowernumber ), 'Integer values are not coded as strings' );
200
208
201
    my $rfc3999_regex = qr/
209
    my $rfc3999_regex = qr/
202
            (?<year>\d{4})
210
            (?<year>\d{4})
Lines 212-222 subtest 'TO_JSON tests' => sub { Link Here
212
            (?<second>\d{2})
220
            (?<second>\d{2})
213
            (([Zz])|([\+|\-]([01][0-9]|2[0-3]):[0-5][0-9]))
221
            (([Zz])|([\+|\-]([01][0-9]|2[0-3]):[0-5][0-9]))
214
        /xms;
222
        /xms;
215
    like( $updated_on, $rfc3999_regex, "Date-time $updated_on formatted correctly");
223
    like( $updated_on, $rfc3999_regex, "Date-time $updated_on formatted correctly" );
216
    like( $lastseen, $rfc3999_regex, "Date-time $lastseen formatted correctly");
224
    like( $lastseen,   $rfc3999_regex, "Date-time $lastseen formatted correctly" );
217
225
218
    # Test JSON doesn't receive strings
226
    # Test JSON doesn't receive strings
219
    my $order = $builder->build_object({ class => 'Koha::Acquisition::Orders' });
227
    my $order = $builder->build_object( { class => 'Koha::Acquisition::Orders' } );
220
    $order = Koha::Acquisition::Orders->find( $order->ordernumber );
228
    $order = Koha::Acquisition::Orders->find( $order->ordernumber );
221
    is_deeply( $order->TO_JSON, decode_json( encode_json( $order->TO_JSON ) ), 'Orders are similar' );
229
    is_deeply( $order->TO_JSON, decode_json( encode_json( $order->TO_JSON ) ), 'Orders are similar' );
222
230
Lines 229-235 subtest "to_api() tests" => sub { Link Here
229
237
230
    $schema->storage->txn_begin;
238
    $schema->storage->txn_begin;
231
239
232
    my $city = $builder->build_object({ class => 'Koha::Cities' });
240
    my $city = $builder->build_object( { class => 'Koha::Cities' } );
233
241
234
    # THE mapping
242
    # THE mapping
235
    # cityid       => 'city_id',
243
    # cityid       => 'city_id',
Lines 248-254 subtest "to_api() tests" => sub { Link Here
248
256
249
    # Lets emulate an undef
257
    # Lets emulate an undef
250
    my $city_class = Test::MockModule->new('Koha::City');
258
    my $city_class = Test::MockModule->new('Koha::City');
251
    $city_class->mock( 'to_api_mapping',
259
    $city_class->mock(
260
        'to_api_mapping',
252
        sub {
261
        sub {
253
            return {
262
            return {
254
                cityid       => 'city_id',
263
                cityid       => 'city_id',
Lines 262-306 subtest "to_api() tests" => sub { Link Here
262
271
263
    $api_city = $city->to_api;
272
    $api_city = $city->to_api;
264
273
265
    is( $api_city->{city_id},     $city->cityid,       'Attribute translated correctly' );
274
    is( $api_city->{city_id}, $city->cityid,       'Attribute translated correctly' );
266
    is( $api_city->{country},     $city->city_country, 'Attribute translated correctly' );
275
    is( $api_city->{country}, $city->city_country, 'Attribute translated correctly' );
267
    is( $api_city->{name},        $city->city_name,    'Attribute translated correctly' );
276
    is( $api_city->{name},    $city->city_name,    'Attribute translated correctly' );
268
    is( $api_city->{state},       $city->city_state,   'Attribute translated correctly' );
277
    is( $api_city->{state},   $city->city_state,   'Attribute translated correctly' );
269
    ok( !exists $api_city->{postal_code}, 'Attribute removed' );
278
    ok( !exists $api_city->{postal_code}, 'Attribute removed' );
270
279
271
    # Pick a class that won't have a mapping for the API
280
    # Pick a class that won't have a mapping for the API
272
    my $action_log = $builder->build_object({ class => 'Koha::ActionLogs' });
281
    my $action_log = $builder->build_object( { class => 'Koha::ActionLogs' } );
273
    is_deeply( $action_log->to_api, $action_log->TO_JSON, 'If no overloaded to_api_mapping method, return TO_JSON' );
282
    is_deeply( $action_log->to_api, $action_log->TO_JSON, 'If no overloaded to_api_mapping method, return TO_JSON' );
274
283
275
    my $biblio = $builder->build_sample_biblio();
284
    my $biblio = $builder->build_sample_biblio();
276
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
285
    my $item   = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
277
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } });
286
    my $hold   = $builder->build_object( { class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } } );
278
287
279
    my $embeds = { 'items' => {} };
288
    my $embeds = { 'items' => {} };
280
289
281
    my $biblio_api = $biblio->to_api({ embed => $embeds });
290
    my $biblio_api = $biblio->to_api( { embed => $embeds } );
282
291
283
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
292
    ok( exists $biblio_api->{items}, 'Items where embedded in biblio results' );
284
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item matches');
293
    is( $biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item matches' );
285
    ok(!exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet');
294
    ok( !exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet' );
286
295
287
    $embeds = (
296
    $embeds = (
288
        {
297
        {
289
            'items' => {
298
            'items'      => { 'children' => { 'holds' => {} } },
290
                'children' => {
291
                    'holds' => {}
292
                }
293
            },
294
            'biblioitem' => {}
299
            'biblioitem' => {}
295
        }
300
        }
296
    );
301
    );
297
    $biblio_api = $biblio->to_api({ embed => $embeds });
302
    $biblio_api = $biblio->to_api( { embed => $embeds } );
298
303
299
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
304
    ok( exists $biblio_api->{items}, 'Items where embedded in biblio results' );
300
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
305
    is( $biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches' );
301
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
306
    ok( exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded' );
302
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches');
307
    is( $biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches' );
303
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
308
    is_deeply( $biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root' );
304
309
305
    my $_strings = {
310
    my $_strings = {
306
        location => {
311
        location => {
Lines 319-331 subtest "to_api() tests" => sub { Link Here
319
        }
324
        }
320
    );
325
    );
321
326
322
    my $hold_api = $hold->to_api(
327
    my $hold_api = $hold->to_api( { embed => { 'item' => { strings => 1 } } } );
323
        {
324
            embed => { 'item' => { strings => 1 } }
325
        }
326
    );
327
328
328
    is( ref($hold_api->{item}), 'HASH', 'Single nested object works correctly' );
329
    is( ref( $hold_api->{item} ),     'HASH',            'Single nested object works correctly' );
329
    is( $hold_api->{item}->{item_id}, $item->itemnumber, 'Object embedded correctly' );
330
    is( $hold_api->{item}->{item_id}, $item->itemnumber, 'Object embedded correctly' );
330
    is_deeply(
331
    is_deeply(
331
        $hold_api->{item}->{_strings},
332
        $hold_api->{item}->{_strings},
Lines 334-360 subtest "to_api() tests" => sub { Link Here
334
    );
335
    );
335
336
336
    # biblio with no items
337
    # biblio with no items
337
    my $new_biblio = $builder->build_sample_biblio;
338
    my $new_biblio     = $builder->build_sample_biblio;
338
    my $new_biblio_api = $new_biblio->to_api({ embed => $embeds });
339
    my $new_biblio_api = $new_biblio->to_api( { embed => $embeds } );
339
340
340
    is_deeply( $new_biblio_api->{items}, [], 'Empty list if no items' );
341
    is_deeply( $new_biblio_api->{items}, [], 'Empty list if no items' );
341
342
342
    my $biblio_class = Test::MockModule->new('Koha::Biblio');
343
    my $biblio_class = Test::MockModule->new('Koha::Biblio');
343
    $biblio_class->mock( 'undef_result', sub { return; } );
344
    $biblio_class->mock( 'undef_result', sub { return; } );
344
345
345
    $new_biblio_api = $new_biblio->to_api({ embed => ( { 'undef_result' => {} } ) });
346
    $new_biblio_api = $new_biblio->to_api( { embed => ( { 'undef_result' => {} } ) } );
346
    ok( exists $new_biblio_api->{undef_result}, 'If a method returns undef, then the attribute is defined' );
347
    ok( exists $new_biblio_api->{undef_result}, 'If a method returns undef, then the attribute is defined' );
347
    is( $new_biblio_api->{undef_result}, undef, 'If a method returns undef, then the attribute is undef' );
348
    is( $new_biblio_api->{undef_result}, undef, 'If a method returns undef, then the attribute is undef' );
348
349
349
    $biblio_class->mock( 'items',
350
    $biblio_class->mock(
350
        sub { return [ bless { itemnumber => 1 }, 'Somethings' ]; } );
351
        'items',
352
        sub { return [ bless { itemnumber => 1 }, 'Somethings' ]; }
353
    );
351
354
352
    throws_ok {
355
    throws_ok {
353
        $new_biblio_api = $new_biblio->to_api(
356
        $new_biblio_api = $new_biblio->to_api( { embed => { 'items' => { children => { asd => {} } } } } );
354
            { embed => { 'items' => { children => { asd => {} } } } } );
355
    }
357
    }
356
    'Koha::Exception',
358
    'Koha::Exception',
357
"An exception is thrown if a blessed object to embed doesn't implement to_api";
359
        "An exception is thrown if a blessed object to embed doesn't implement to_api";
358
360
359
    is(
361
    is(
360
        $@->message,
362
        $@->message,
Lines 362-368 subtest "to_api() tests" => sub { Link Here
362
        "Exception message correct"
364
        "Exception message correct"
363
    );
365
    );
364
366
365
366
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
367
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
367
    $builder->build_object(
368
    $builder->build_object(
368
        {
369
        {
Lines 401-416 subtest "to_api() tests" => sub { Link Here
401
402
402
    subtest 'public request tests' => sub {
403
    subtest 'public request tests' => sub {
403
404
404
        my @all_attrs = Koha::Libraries->columns();
405
        my @all_attrs    = Koha::Libraries->columns();
405
        my $public_attrs = { map { $_ => 1 } @{ Koha::Library->public_read_list() } };
406
        my $public_attrs = { map { $_ => 1 } @{ Koha::Library->public_read_list() } };
406
        my $mapping = Koha::Library->to_api_mapping;
407
        my $mapping      = Koha::Library->to_api_mapping;
407
408
408
        plan tests => scalar @all_attrs * 2;
409
        plan tests => scalar @all_attrs * 2;
409
410
410
        # Create a sample library
411
        # Create a sample library
411
        my $library = $builder->build_object( { class => 'Koha::Libraries' } );
412
        my $library = $builder->build_object( { class => 'Koha::Libraries' } );
412
413
413
        my $unprivileged_representation = $library->to_api({ public => 1 });
414
        my $unprivileged_representation = $library->to_api( { public => 1 } );
414
        my $privileged_representation   = $library->to_api;
415
        my $privileged_representation   = $library->to_api;
415
416
416
        foreach my $attr (@all_attrs) {
417
        foreach my $attr (@all_attrs) {
Lines 425-439 subtest "to_api() tests" => sub { Link Here
425
                        exists $unprivileged_representation->{$mapped},
426
                        exists $unprivileged_representation->{$mapped},
426
                        "Attribute '$attr' is present when public"
427
                        "Attribute '$attr' is present when public"
427
                    );
428
                    );
428
                }
429
                } else {
429
                else {
430
                    ok(
430
                    ok(
431
                        !exists $unprivileged_representation->{$mapped},
431
                        !exists $unprivileged_representation->{$mapped},
432
                        "Attribute '$attr' is not present when public"
432
                        "Attribute '$attr' is not present when public"
433
                    );
433
                    );
434
                }
434
                }
435
            }
435
            } else {
436
            else {
437
                ok(
436
                ok(
438
                    !exists $privileged_representation->{$attr},
437
                    !exists $privileged_representation->{$attr},
439
                    "Unmapped attribute '$attr' is not present when privileged"
438
                    "Unmapped attribute '$attr' is not present when privileged"
Lines 453-462 subtest "to_api() tests" => sub { Link Here
453
        $schema->storage->txn_begin;
452
        $schema->storage->txn_begin;
454
453
455
        # new category
454
        # new category
456
        my $category = $builder->build_object({ class => 'Koha::AuthorisedValueCategories' });
455
        my $category = $builder->build_object( { class => 'Koha::AuthorisedValueCategories' } );
456
457
        # add two countries
457
        # add two countries
458
        my $argentina = $builder->build_object(
458
        my $argentina = $builder->build_object(
459
            {   class => 'Koha::AuthorisedValues',
459
            {
460
                class => 'Koha::AuthorisedValues',
460
                value => {
461
                value => {
461
                    category => $category->category_name,
462
                    category => $category->category_name,
462
                    lib      => 'AR (Argentina)',
463
                    lib      => 'AR (Argentina)',
Lines 465-471 subtest "to_api() tests" => sub { Link Here
465
            }
466
            }
466
        );
467
        );
467
        my $france = $builder->build_object(
468
        my $france = $builder->build_object(
468
            {   class => 'Koha::AuthorisedValues',
469
            {
470
                class => 'Koha::AuthorisedValues',
469
                value => {
471
                value => {
470
                    category => $category->category_name,
472
                    category => $category->category_name,
471
                    lib      => 'FR (France)',
473
                    lib      => 'FR (France)',
Lines 499-510 subtest "to_api() tests" => sub { Link Here
499
        $city_mock->mock( 'public_read_list', sub { return [ 'city_id', 'city_country', 'city_name', 'city_state' ] } );
501
        $city_mock->mock( 'public_read_list', sub { return [ 'city_id', 'city_country', 'city_name', 'city_state' ] } );
500
502
501
        my $cordoba = $builder->build_object(
503
        my $cordoba = $builder->build_object(
502
            {   class => 'Koha::Cities',
504
            {
505
                class => 'Koha::Cities',
503
                value => { city_country => $argentina->authorised_value, city_name => 'Cordoba' }
506
                value => { city_country => $argentina->authorised_value, city_name => 'Cordoba' }
504
            }
507
            }
505
        );
508
        );
506
        my $marseille = $builder->build_object(
509
        my $marseille = $builder->build_object(
507
            {   class => 'Koha::Cities',
510
            {
511
                class => 'Koha::Cities',
508
                value => { city_country => $france->authorised_value, city_name => 'Marseille' }
512
                value => { city_country => $france->authorised_value, city_name => 'Marseille' }
509
            }
513
            }
510
        );
514
        );
Lines 621-627 subtest "to_api_mapping() tests" => sub { Link Here
621
625
622
    $schema->storage->txn_begin;
626
    $schema->storage->txn_begin;
623
627
624
    my $action_log = $builder->build_object({ class => 'Koha::ActionLogs' });
628
    my $action_log = $builder->build_object( { class => 'Koha::ActionLogs' } );
625
    is_deeply( $action_log->to_api_mapping, {}, 'If no to_api_mapping present, return empty hashref' );
629
    is_deeply( $action_log->to_api_mapping, {}, 'If no to_api_mapping present, return empty hashref' );
626
630
627
    $schema->storage->txn_rollback;
631
    $schema->storage->txn_rollback;
Lines 633-643 subtest "from_api_mapping() tests" => sub { Link Here
633
637
634
    $schema->storage->txn_begin;
638
    $schema->storage->txn_begin;
635
639
636
    my $city = $builder->build_object({ class => 'Koha::Cities' });
640
    my $city = $builder->build_object( { class => 'Koha::Cities' } );
637
641
638
    # Lets emulate an undef
642
    # Lets emulate an undef
639
    my $city_class = Test::MockModule->new('Koha::City');
643
    my $city_class = Test::MockModule->new('Koha::City');
640
    $city_class->mock( 'to_api_mapping',
644
    $city_class->mock(
645
        'to_api_mapping',
641
        sub {
646
        sub {
642
            return {
647
            return {
643
                cityid       => 'city_id',
648
                cityid       => 'city_id',
Lines 656-663 subtest "from_api_mapping() tests" => sub { Link Here
656
        'Mapping returns correctly, undef ommited'
661
        'Mapping returns correctly, undef ommited'
657
    );
662
    );
658
663
659
    $city_class->unmock( 'to_api_mapping');
664
    $city_class->unmock('to_api_mapping');
660
    $city_class->mock( 'to_api_mapping',
665
    $city_class->mock(
666
        'to_api_mapping',
661
        sub {
667
        sub {
662
            return {
668
            return {
663
                cityid       => 'city_id',
669
                cityid       => 'city_id',
Lines 677-683 subtest "from_api_mapping() tests" => sub { Link Here
677
    );
683
    );
678
684
679
    # Get a fresh object
685
    # Get a fresh object
680
    $city = $builder->build_object({ class => 'Koha::Cities' });
686
    $city = $builder->build_object( { class => 'Koha::Cities' } );
681
    is_deeply(
687
    is_deeply(
682
        $city->from_api_mapping,
688
        $city->from_api_mapping,
683
        {
689
        {
Lines 688-709 subtest "from_api_mapping() tests" => sub { Link Here
688
        'Fresh mapping loaded'
694
        'Fresh mapping loaded'
689
    );
695
    );
690
696
691
    $city_class->unmock( 'to_api_mapping');
697
    $city_class->unmock('to_api_mapping');
692
    $city_class->mock( 'to_api_mapping', undef );
698
    $city_class->mock( 'to_api_mapping', undef );
693
699
694
    # Get a fresh object
700
    # Get a fresh object
695
    $city = $builder->build_object({ class => 'Koha::Cities' });
701
    $city = $builder->build_object( { class => 'Koha::Cities' } );
696
    is_deeply(
702
    is_deeply(
697
        $city->from_api_mapping,
703
        $city->from_api_mapping,
698
        {},
704
        {},
699
        'No to_api_mapping then empty hashref'
705
        'No to_api_mapping then empty hashref'
700
    );
706
    );
701
707
702
    $city_class->unmock( 'to_api_mapping');
708
    $city_class->unmock('to_api_mapping');
703
    $city_class->mock( 'to_api_mapping', sub { return; } );
709
    $city_class->mock( 'to_api_mapping', sub { return; } );
704
710
705
    # Get a fresh object
711
    # Get a fresh object
706
    $city = $builder->build_object({ class => 'Koha::Cities' });
712
    $city = $builder->build_object( { class => 'Koha::Cities' } );
707
    is_deeply(
713
    is_deeply(
708
        $city->from_api_mapping,
714
        $city->from_api_mapping,
709
        {},
715
        {},
Lines 719-737 subtest 'set_from_api() tests' => sub { Link Here
719
725
720
    $schema->storage->txn_begin;
726
    $schema->storage->txn_begin;
721
727
722
    my $city = $builder->build_object({ class => 'Koha::Cities' });
728
    my $city           = $builder->build_object( { class => 'Koha::Cities' } );
723
    my $city_unblessed = $city->unblessed;
729
    my $city_unblessed = $city->unblessed;
724
    my $attrs = {
730
    my $attrs          = {
725
        name        => 'Cordoba',
731
        name        => 'Cordoba',
726
        country     => 'Argentina',
732
        country     => 'Argentina',
727
        postal_code => '5000'
733
        postal_code => '5000'
728
    };
734
    };
729
    $city->set_from_api($attrs);
735
    $city->set_from_api($attrs);
730
736
731
    is( $city->city_state, $city_unblessed->{city_state}, 'Untouched attributes are preserved' );
737
    is( $city->city_state,   $city_unblessed->{city_state}, 'Untouched attributes are preserved' );
732
    is( $city->city_name, $attrs->{name}, 'city_name updated correctly' );
738
    is( $city->city_name,    $attrs->{name},                'city_name updated correctly' );
733
    is( $city->city_country, $attrs->{country}, 'city_country updated correctly' );
739
    is( $city->city_country, $attrs->{country},             'city_country updated correctly' );
734
    is( $city->city_zipcode, $attrs->{postal_code}, 'city_zipcode updated correctly' );
740
    is( $city->city_zipcode, $attrs->{postal_code},         'city_zipcode updated correctly' );
735
741
736
    $schema->storage->txn_rollback;
742
    $schema->storage->txn_rollback;
737
};
743
};
Lines 749-757 subtest 'new_from_api() tests' => sub { Link Here
749
    };
755
    };
750
    my $city = Koha::City->new_from_api($attrs);
756
    my $city = Koha::City->new_from_api($attrs);
751
757
752
    is( ref($city), 'Koha::City', 'Object type is correct' );
758
    is( ref($city),          'Koha::City',          'Object type is correct' );
753
    is( $city->city_name,    $attrs->{name}, 'city_name updated correctly' );
759
    is( $city->city_name,    $attrs->{name},        'city_name updated correctly' );
754
    is( $city->city_country, $attrs->{country}, 'city_country updated correctly' );
760
    is( $city->city_country, $attrs->{country},     'city_country updated correctly' );
755
    is( $city->city_zipcode, $attrs->{postal_code}, 'city_zipcode updated correctly' );
761
    is( $city->city_zipcode, $attrs->{postal_code}, 'city_zipcode updated correctly' );
756
762
757
    $schema->storage->txn_rollback;
763
    $schema->storage->txn_rollback;
Lines 773-802 subtest 'attributes_from_api() tests' => sub { Link Here
773
779
774
        my $attrs = $patron->attributes_from_api(
780
        my $attrs = $patron->attributes_from_api(
775
            {
781
            {
776
                updated_on     => '2019-12-27T14:53:00Z',
782
                updated_on    => '2019-12-27T14:53:00Z',
777
                last_seen      => '2019-12-27T14:53:00Z',
783
                last_seen     => '2019-12-27T14:53:00Z',
778
                date_of_birth  => '2019-12-27',
784
                date_of_birth => '2019-12-27',
779
            }
785
            }
780
        );
786
        );
781
787
782
        ok( exists $attrs->{updated_on},
788
        ok(
783
            'No translation takes place if no mapping' );
789
            exists $attrs->{updated_on},
790
            'No translation takes place if no mapping'
791
        );
784
        is(
792
        is(
785
            $attrs->{updated_on},
793
            $attrs->{updated_on},
786
            '2019-12-27 14:53:00',
794
            '2019-12-27 14:53:00',
787
            'Given an rfc3339 formatted datetime string, a timestamp field is converted into an SQL formatted datetime string'
795
            'Given an rfc3339 formatted datetime string, a timestamp field is converted into an SQL formatted datetime string'
788
        );
796
        );
789
797
790
        ok( exists $attrs->{lastseen},
798
        ok(
791
            'Translation takes place because of the defined mapping' );
799
            exists $attrs->{lastseen},
800
            'Translation takes place because of the defined mapping'
801
        );
792
        is(
802
        is(
793
            $attrs->{lastseen},
803
            $attrs->{lastseen},
794
            '2019-12-27 14:53:00',
804
            '2019-12-27 14:53:00',
795
            'Given an rfc3339 formatted datetime string, a datetime field is converted into an SQL formatted datetime string'
805
            'Given an rfc3339 formatted datetime string, a datetime field is converted into an SQL formatted datetime string'
796
        );
806
        );
797
807
798
        ok( exists $attrs->{dateofbirth},
808
        ok(
799
            'Translation takes place because of the defined mapping' );
809
            exists $attrs->{dateofbirth},
810
            'Translation takes place because of the defined mapping'
811
        );
800
        is(
812
        is(
801
            $attrs->{dateofbirth},
813
            $attrs->{dateofbirth},
802
            '2019-12-27',
814
            '2019-12-27',
Lines 820-862 subtest 'attributes_from_api() tests' => sub { Link Here
820
                    },
832
                    },
821
                    { '=' => '2019-12-31 23:59:00' }
833
                    { '=' => '2019-12-31 23:59:00' }
822
                ],
834
                ],
823
                updated_on => { '>' => '2019-12-27 14:53:00' },
835
                updated_on  => { '>' => '2019-12-27 14:53:00' },
824
                dateofbirth => [ { '>', '2019-12-27'}, { '=' => '2019-12-31' } ]
836
                dateofbirth => [ { '>', '2019-12-27' }, { '=' => '2019-12-31' } ]
825
            }
837
            }
826
        );
838
        );
827
839
828
        $attrs = $patron->attributes_from_api(
840
        $attrs = $patron->attributes_from_api(
829
            {
841
            {
830
                last_seen      => undef,
842
                last_seen     => undef,
831
                date_of_birth  => undef,
843
                date_of_birth => undef,
832
            }
844
            }
833
        );
845
        );
834
846
835
        ok( exists $attrs->{lastseen},
847
        ok(
836
            'undef parameter is not skipped (Bug 29157)' );
848
            exists $attrs->{lastseen},
849
            'undef parameter is not skipped (Bug 29157)'
850
        );
837
        is(
851
        is(
838
            $attrs->{lastseen},
852
            $attrs->{lastseen},
839
            undef,
853
            undef,
840
            'Given undef, a datetime field is set to undef (Bug 29157)'
854
            'Given undef, a datetime field is set to undef (Bug 29157)'
841
        );
855
        );
842
856
843
        ok( exists $attrs->{dateofbirth},
857
        ok(
844
            'undef parameter is not skipped (Bug 29157)' );
858
            exists $attrs->{dateofbirth},
859
            'undef parameter is not skipped (Bug 29157)'
860
        );
845
        is(
861
        is(
846
            $attrs->{dateofbirth},
862
            $attrs->{dateofbirth},
847
            undef,
863
            undef,
848
            'Given undef, a date field is set to undef (Bug 29157)'
864
            'Given undef, a date field is set to undef (Bug 29157)'
849
        );
865
        );
850
866
851
        throws_ok
867
        throws_ok {
852
            {
868
            $attrs = $patron->attributes_from_api(
853
                $attrs = $patron->attributes_from_api(
869
                {
854
                    {
870
                    date_of_birth => '20141205',
855
                        date_of_birth => '20141205',
871
                }
856
                    }
872
            );
857
                );
873
        }
858
            }
874
        'Koha::Exceptions::BadParameter',
859
            'Koha::Exceptions::BadParameter',
860
            'Bad date throws an exception';
875
            'Bad date throws an exception';
861
876
862
        is(
877
        is(
Lines 894-916 subtest "Test update method" => sub { Link Here
894
909
895
    $schema->storage->txn_begin;
910
    $schema->storage->txn_begin;
896
911
897
    my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
912
    my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
898
    my $library = Koha::Libraries->find( $branchcode );
913
    my $library    = Koha::Libraries->find($branchcode);
899
    $library->update({ branchname => 'New_Name', branchcity => 'AMS' });
914
    $library->update( { branchname => 'New_Name', branchcity => 'AMS' } );
900
    is( $library->branchname, 'New_Name', 'Changed name with update' );
915
    is( $library->branchname, 'New_Name', 'Changed name with update' );
901
    is( $library->branchcity, 'AMS', 'Changed city too' );
916
    is( $library->branchcity, 'AMS',      'Changed city too' );
902
    is( $library->is_changed, 0, 'Change should be stored already' );
917
    is( $library->is_changed, 0,          'Change should be stored already' );
903
    try {
918
    try {
904
        $library->update({
919
        $library->update(
905
            branchcity => 'NYC', not_a_column => 53, branchname => 'Name3',
920
            {
906
        });
921
                branchcity => 'NYC', not_a_column => 53, branchname => 'Name3',
907
        fail( 'It should not be possible to update an unexisting column without an error from Koha::Object/DBIx' );
922
            }
923
        );
924
        fail('It should not be possible to update an unexisting column without an error from Koha::Object/DBIx');
908
    } catch {
925
    } catch {
909
        ok( $_->isa('Koha::Exceptions::Object'), 'Caught error when updating wrong column' );
926
        ok( $_->isa('Koha::Exceptions::Object'), 'Caught error when updating wrong column' );
910
        $library->discard_changes; #requery after failing update
927
        $library->discard_changes;    #requery after failing update
911
    };
928
    };
929
912
    # Check if the columns are not updated
930
    # Check if the columns are not updated
913
    is( $library->branchcity, 'AMS', 'First column not updated' );
931
    is( $library->branchcity, 'AMS',      'First column not updated' );
914
    is( $library->branchname, 'New_Name', 'Third column not updated' );
932
    is( $library->branchname, 'New_Name', 'Third column not updated' );
915
933
916
    $schema->storage->txn_rollback;
934
    $schema->storage->txn_rollback;
Lines 926-939 subtest 'store() tests' => sub { Link Here
926
    $schema->storage->txn_begin;
944
    $schema->storage->txn_begin;
927
945
928
    # Create a library to make sure its ID doesn't exist on the DB
946
    # Create a library to make sure its ID doesn't exist on the DB
929
    my $library = $builder->build_object({ class => 'Koha::Libraries' });
947
    my $library    = $builder->build_object( { class => 'Koha::Libraries' } );
930
    my $branchcode = $library->branchcode;
948
    my $branchcode = $library->branchcode;
931
    $library->delete;
949
    $library->delete;
932
950
933
    my $library_group = Koha::Library::Group->new(
951
    my $library_group = Koha::Library::Group->new(
934
        {
952
        {
935
            branchcode      => $library->branchcode,
953
            branchcode => $library->branchcode,
936
            title => 'a title',
954
            title      => 'a title',
937
        }
955
        }
938
    );
956
    );
939
957
Lines 941-949 subtest 'store() tests' => sub { Link Here
941
    {
959
    {
942
        local *STDERR;
960
        local *STDERR;
943
        open STDERR, '>', '/dev/null';
961
        open STDERR, '>', '/dev/null';
944
        throws_ok
962
        throws_ok { $library_group->store }
945
            { $library_group->store }
963
        'Koha::Exceptions::Object::FKConstraint',
946
            'Koha::Exceptions::Object::FKConstraint',
947
            'Exception is thrown correctly';
964
            'Exception is thrown correctly';
948
        is(
965
        is(
949
            $@->message,
966
            $@->message,
Lines 956-973 subtest 'store() tests' => sub { Link Here
956
            'Exception field is correct'
973
            'Exception field is correct'
957
        );
974
        );
958
975
959
        $library_group = $builder->build_object({ class => 'Koha::Library::Groups' });
976
        $library_group = $builder->build_object( { class => 'Koha::Library::Groups' } );
960
977
961
        my $new_library_group = Koha::Library::Group->new(
978
        my $new_library_group = Koha::Library::Group->new(
962
            {
979
            {
963
                branchcode      => $library_group->branchcode,
980
                branchcode => $library_group->branchcode,
964
                title        => $library_group->title,
981
                title      => $library_group->title,
965
            }
982
            }
966
        );
983
        );
967
984
968
        throws_ok
985
        throws_ok { $new_library_group->store }
969
            { $new_library_group->store }
986
        'Koha::Exceptions::Object::DuplicateID',
970
            'Koha::Exceptions::Object::DuplicateID',
971
            'Exception is thrown correctly';
987
            'Exception is thrown correctly';
972
988
973
        is(
989
        is(
Lines 977-991 subtest 'store() tests' => sub { Link Here
977
        );
993
        );
978
994
979
        like(
995
        like(
980
           $@->duplicate_id,
996
            $@->duplicate_id,
981
           qr/(library_groups\.)?title/,
997
            qr/(library_groups\.)?title/,
982
           'Exception field is correct (note that MySQL 8 is displaying the tablename)'
998
            'Exception field is correct (note that MySQL 8 is displaying the tablename)'
983
        );
999
        );
984
        close STDERR;
1000
        close STDERR;
985
    }
1001
    }
986
1002
987
    # Successful test
1003
    # Successful test
988
    $library_group->set({ title => 'Manuel' });
1004
    $library_group->set( { title => 'Manuel' } );
989
    my $ret = $library_group->store;
1005
    my $ret = $library_group->store;
990
    is( ref($ret), 'Koha::Library::Group', 'store() returns the object on success' );
1006
    is( ref($ret), 'Koha::Library::Group', 'store() returns the object on success' );
991
1007
Lines 1002-1048 subtest 'store() tests' => sub { Link Here
1002
            {
1018
            {
1003
                categorycode    => $patron_category->categorycode,
1019
                categorycode    => $patron_category->categorycode,
1004
                branchcode      => $library->branchcode,
1020
                branchcode      => $library->branchcode,
1005
                dateofbirth     => "", # date will be set to NULL
1021
                dateofbirth     => "",                               # date will be set to NULL
1006
                sms_provider_id => "", # Integer will be set to NULL
1022
                sms_provider_id => "",                               # Integer will be set to NULL
1007
                privacy         => "", # privacy cannot be NULL but has a default value
1023
                privacy         => "",                               # privacy cannot be NULL but has a default value
1008
            }
1024
            }
1009
        )->store;
1025
        )->store;
1010
    };
1026
    };
1011
    is( $@, '', 'No error should be raised by ->store if empty strings are passed' );
1027
    is( $@,                       '',    'No error should be raised by ->store if empty strings are passed' );
1012
    is( $patron->privacy, 1, 'Default value for privacy should be set to 1' );
1028
    is( $patron->privacy,         1,     'Default value for privacy should be set to 1' );
1013
    is( $patron->dateofbirth,     undef, 'dateofbirth must have been set to undef');
1029
    is( $patron->dateofbirth,     undef, 'dateofbirth must have been set to undef' );
1014
    is( $patron->sms_provider_id, undef, 'sms_provider_id must have been set to undef');
1030
    is( $patron->sms_provider_id, undef, 'sms_provider_id must have been set to undef' );
1015
1031
1016
    my $itemtype = eval {
1032
    my $itemtype = eval {
1017
        Koha::ItemType->new(
1033
        Koha::ItemType->new(
1018
            {
1034
            {
1019
                itemtype        => 'IT4test',
1035
                itemtype     => 'IT4test',
1020
                rentalcharge    => "",
1036
                rentalcharge => "",
1021
                notforloan      => "",
1037
                notforloan   => "",
1022
                hideinopac      => "",
1038
                hideinopac   => "",
1023
            }
1039
            }
1024
        )->store;
1040
        )->store;
1025
    };
1041
    };
1026
    is( $@, '', 'No error should be raised by ->store if empty strings are passed' );
1042
    is( $@,                      '',    'No error should be raised by ->store if empty strings are passed' );
1027
    is( $itemtype->rentalcharge, undef, 'decimal DEFAULT NULL should default to null');
1043
    is( $itemtype->rentalcharge, undef, 'decimal DEFAULT NULL should default to null' );
1028
    is( $itemtype->hideinopac, 0, 'int NOT NULL DEFAULT 0 should default to 0');
1044
    is( $itemtype->hideinopac,   0,     'int NOT NULL DEFAULT 0 should default to 0' );
1029
1045
1030
    my $currency = eval {
1046
    my $currency = eval {
1031
        Koha::Acquisition::Currency->new(
1047
        Koha::Acquisition::Currency->new(
1032
            {
1048
            {
1033
                currency      => 'Cur_test',
1049
                currency => 'Cur_test',
1034
                active        => 'IT4test',
1050
                active   => 'IT4test',
1035
            }
1051
            }
1036
        )->store;
1052
        )->store;
1037
    };
1053
    };
1038
    is( $currency->active, undef, 'int DEFAULT NULL should default to null');
1054
    is( $currency->active, undef, 'int DEFAULT NULL should default to null' );
1039
1055
1040
    subtest 'Bad value tests' => sub {
1056
    subtest 'Bad value tests' => sub {
1041
1057
1042
        plan tests => 3;
1058
        plan tests => 3;
1043
1059
1044
        my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1060
        my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
1045
1046
1061
1047
        try {
1062
        try {
1048
            local *STDERR;
1063
            local *STDERR;
Lines 1051-1057 subtest 'store() tests' => sub { Link Here
1051
            close STDERR;
1066
            close STDERR;
1052
        } catch {
1067
        } catch {
1053
            ok( $_->isa('Koha::Exceptions::Object::BadValue'), 'Exception thrown correctly' );
1068
            ok( $_->isa('Koha::Exceptions::Object::BadValue'), 'Exception thrown correctly' );
1054
            like( $_->property, qr/(borrowers\.)?lastseen/, 'Column should be the expected one' ); # The table name is not always displayed, it depends on the DBMS version
1069
            like( $_->property, qr/(borrowers\.)?lastseen/, 'Column should be the expected one' )
1070
                ;    # The table name is not always displayed, it depends on the DBMS version
1055
            is( $_->value, 'wrong_value', 'Value should be the expected one' );
1071
            is( $_->value, 'wrong_value', 'Value should be the expected one' );
1056
        };
1072
        };
1057
    };
1073
    };
Lines 1066-1072 subtest 'unblessed_all_relateds' => sub { Link Here
1066
1082
1067
    # FIXME It's very painful to create an issue in tests!
1083
    # FIXME It's very painful to create an issue in tests!
1068
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
1084
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
1069
    t::lib::Mocks::mock_userenv({ branchcode => $library->branchcode });
1085
    t::lib::Mocks::mock_userenv( { branchcode => $library->branchcode } );
1070
1086
1071
    my $patron_category = $builder->build(
1087
    my $patron_category = $builder->build(
1072
        {
1088
        {
Lines 1079-1094 subtest 'unblessed_all_relateds' => sub { Link Here
1079
        }
1095
        }
1080
    );
1096
    );
1081
    my $patron_data = {
1097
    my $patron_data = {
1082
        firstname =>  'firstname',
1098
        firstname    => 'firstname',
1083
        surname => 'surname',
1099
        surname      => 'surname',
1084
        categorycode => $patron_category->{categorycode},
1100
        categorycode => $patron_category->{categorycode},
1085
        branchcode => $library->branchcode,
1101
        branchcode   => $library->branchcode,
1086
    };
1102
    };
1087
    my $patron = Koha::Patron->new($patron_data)->store;
1103
    my $patron         = Koha::Patron->new($patron_data)->store;
1088
    my ($biblionumber) = AddBiblio( MARC::Record->new, '' );
1104
    my ($biblionumber) = AddBiblio( MARC::Record->new, '' );
1089
    my $biblio = Koha::Biblios->find( $biblionumber );
1105
    my $biblio         = Koha::Biblios->find($biblionumber);
1090
    my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
1106
    my $itemtype       = $builder->build( { source => 'Itemtype' } )->{itemtype};
1091
    my $item = $builder->build_object(
1107
    my $item           = $builder->build_object(
1092
        {
1108
        {
1093
            class => 'Koha::Items',
1109
            class => 'Koha::Items',
1094
            value => {
1110
            value => {
Lines 1102-1112 subtest 'unblessed_all_relateds' => sub { Link Here
1102
        }
1118
        }
1103
    );
1119
    );
1104
1120
1105
    my $issue = AddIssue( $patron, $item->barcode, dt_from_string()->subtract( days => 1 ) );
1121
    my $issue    = AddIssue( $patron, $item->barcode, dt_from_string()->subtract( days => 1 ) );
1106
    my $overdues = Koha::Patrons->find( $patron->id )->overdues; # Koha::Patron->overdues prefetches
1122
    my $overdues = Koha::Patrons->find( $patron->id )->overdues;    # Koha::Patron->overdues prefetches
1107
    my $overdue = $overdues->next->unblessed_all_relateds;
1123
    my $overdue  = $overdues->next->unblessed_all_relateds;
1108
    is( $overdue->{issue_id}, $issue->issue_id, 'unblessed_all_relateds has field from the original table (issues)' );
1124
    is( $overdue->{issue_id},   $issue->issue_id, 'unblessed_all_relateds has field from the original table (issues)' );
1109
    is( $overdue->{title}, $biblio->title, 'unblessed_all_relateds has field from other tables (biblio)' );
1125
    is( $overdue->{title},      $biblio->title,   'unblessed_all_relateds has field from other tables (biblio)' );
1110
    is( $overdue->{homebranch}, $item->homebranch, 'unblessed_all_relateds has field from other tables (items)' );
1126
    is( $overdue->{homebranch}, $item->homebranch, 'unblessed_all_relateds has field from other tables (items)' );
1111
1127
1112
    $schema->storage->txn_rollback;
1128
    $schema->storage->txn_rollback;
Lines 1124-1136 subtest 'get_from_storage' => sub { Link Here
1124
    Koha::Biblios->find( $biblio->biblionumber )->title($new_title)->store;
1140
    Koha::Biblios->find( $biblio->biblionumber )->title($new_title)->store;
1125
1141
1126
    is( $biblio->title, $old_title, 'current $biblio should not be modified' );
1142
    is( $biblio->title, $old_title, 'current $biblio should not be modified' );
1127
    is( $biblio->get_from_storage->title,
1143
    is(
1128
        $new_title, 'get_from_storage should return an updated object' );
1144
        $biblio->get_from_storage->title,
1145
        $new_title, 'get_from_storage should return an updated object'
1146
    );
1129
1147
1130
    Koha::Biblios->find( $biblio->biblionumber )->delete;
1148
    Koha::Biblios->find( $biblio->biblionumber )->delete;
1131
    is( ref($biblio), 'Koha::Biblio', 'current $biblio should not be deleted' );
1149
    is( ref($biblio), 'Koha::Biblio', 'current $biblio should not be deleted' );
1132
    is( $biblio->get_from_storage, undef,
1150
    is(
1133
        'get_from_storage should return undef if the object has been deleted' );
1151
        $biblio->get_from_storage, undef,
1152
        'get_from_storage should return undef if the object has been deleted'
1153
    );
1134
1154
1135
    $schema->storage->txn_rollback;
1155
    $schema->storage->txn_rollback;
1136
};
1156
};
Lines 1170-1199 subtest 'set_or_blank' => sub { Link Here
1170
1190
1171
    $schema->storage->txn_begin;
1191
    $schema->storage->txn_begin;
1172
1192
1173
    my $item = $builder->build_sample_item;
1193
    my $item      = $builder->build_sample_item;
1174
    my $item_info = $item->unblessed;
1194
    my $item_info = $item->unblessed;
1175
    $item = $item->set_or_blank($item_info);
1195
    $item = $item->set_or_blank($item_info);
1176
    is_deeply($item->unblessed, $item_info, 'set_or_blank assign the correct value if unchanged');
1196
    is_deeply( $item->unblessed, $item_info, 'set_or_blank assign the correct value if unchanged' );
1177
1197
1178
    # int not null
1198
    # int not null
1179
    delete $item_info->{itemlost};
1199
    delete $item_info->{itemlost};
1180
    $item = $item->set_or_blank($item_info);
1200
    $item = $item->set_or_blank($item_info);
1181
    is($item->itemlost, 0, 'set_or_blank should have set itemlost to 0, default value defined in DB');
1201
    is( $item->itemlost, 0, 'set_or_blank should have set itemlost to 0, default value defined in DB' );
1182
1202
1183
    # int nullable
1203
    # int nullable
1184
    delete $item_info->{restricted};
1204
    delete $item_info->{restricted};
1185
    $item = $item->set_or_blank($item_info);
1205
    $item = $item->set_or_blank($item_info);
1186
    is($item->restricted, undef, 'set_or_blank should have set restristed to null' );
1206
    is( $item->restricted, undef, 'set_or_blank should have set restristed to null' );
1187
1207
1188
    # datetime nullable
1208
    # datetime nullable
1189
    delete $item_info->{dateaccessioned};
1209
    delete $item_info->{dateaccessioned};
1190
    $item = $item->set_or_blank($item_info);
1210
    $item = $item->set_or_blank($item_info);
1191
    is($item->dateaccessioned, undef, 'set_or_blank should have set dateaccessioned to null');
1211
    is( $item->dateaccessioned, undef, 'set_or_blank should have set dateaccessioned to null' );
1192
1212
1193
    # timestamp not null
1213
    # timestamp not null
1194
    delete $item_info->{timestamp};
1214
    delete $item_info->{timestamp};
1195
    $item = $item->set_or_blank($item_info);
1215
    $item = $item->set_or_blank($item_info);
1196
    isnt($item->timestamp, undef, 'set_or_blank should have set timestamp to a correct value');
1216
    isnt( $item->timestamp, undef, 'set_or_blank should have set timestamp to a correct value' );
1197
1217
1198
    $schema->storage->txn_rollback;
1218
    $schema->storage->txn_rollback;
1199
};
1219
};
Lines 1209-1227 subtest 'messages() and add_message() tests' => sub { Link Here
1209
    my @messages = @{ $patron->object_messages };
1229
    my @messages = @{ $patron->object_messages };
1210
    is( scalar @messages, 0, 'No messages' );
1230
    is( scalar @messages, 0, 'No messages' );
1211
1231
1212
    $patron->add_message({ message => "message_1" });
1232
    $patron->add_message( { message => "message_1" } );
1213
    $patron->add_message({ message => "message_2" });
1233
    $patron->add_message( { message => "message_2" } );
1214
1234
1215
    @messages = @{ $patron->object_messages };
1235
    @messages = @{ $patron->object_messages };
1216
1236
1217
    is( scalar @messages, 2, 'Messages are returned' );
1237
    is( scalar @messages,      2,                       'Messages are returned' );
1218
    is( ref($messages[0]), 'Koha::Object::Message', 'Right type returned' );
1238
    is( ref( $messages[0] ),   'Koha::Object::Message', 'Right type returned' );
1219
    is( ref($messages[1]), 'Koha::Object::Message', 'Right type returned' );
1239
    is( ref( $messages[1] ),   'Koha::Object::Message', 'Right type returned' );
1220
    is( $messages[0]->message, 'message_1', 'Right message recorded' );
1240
    is( $messages[0]->message, 'message_1',             'Right message recorded' );
1241
1242
    my $patron_id = $builder->build_object( { class => 'Koha::Patrons' } )->id;
1221
1243
1222
    my $patron_id = $builder->build_object({ class => 'Koha::Patrons' })->id;
1223
    # get a patron from the DB, ->new is not called, ->object_messages should initialize _messages as an empty arrayref
1244
    # get a patron from the DB, ->new is not called, ->object_messages should initialize _messages as an empty arrayref
1224
    $patron = Koha::Patrons->find( $patron_id );
1245
    $patron = Koha::Patrons->find($patron_id);
1225
1246
1226
    isnt( $patron->object_messages, undef, '->messages initializes the array if required' );
1247
    isnt( $patron->object_messages, undef, '->messages initializes the array if required' );
1227
    is( scalar @{ $patron->object_messages }, 0, '->messages returns an empty arrayref' );
1248
    is( scalar @{ $patron->object_messages }, 0, '->messages returns an empty arrayref' );
Lines 1248-1259 subtest 'is_accessible() tests' => sub { Link Here
1248
        }
1269
        }
1249
    );
1270
    );
1250
1271
1251
    my $patron_1 = $builder->build_object(
1272
    my $patron_1 = $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library_1->id } } );
1252
        { class => 'Koha::Patrons', value => { branchcode => $library_1->id } }
1273
    my $patron_2 = $builder->build_object( { class => 'Koha::Patrons', value => { branchcode => $library_2->id } } );
1253
    );
1254
    my $patron_2 = $builder->build_object(
1255
        { class => 'Koha::Patrons', value => { branchcode => $library_2->id } }
1256
    );
1257
1274
1258
    t::lib::Mocks::mock_userenv( { patron => $patron } );
1275
    t::lib::Mocks::mock_userenv( { patron => $patron } );
1259
1276
1260
- 

Return to bug 37902