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

(-)a/Koha/Patron.pm (-35 / +12 lines)
Lines 814-824 sub is_expired { Link Here
814
814
815
$patron->is_active({ [ since => $date ], [ days|weeks|months|years => $value ] })
815
$patron->is_active({ [ since => $date ], [ days|weeks|months|years => $value ] })
816
816
817
A patron is considered 'active' if their account did not expire, and has not been anonymized,
817
A patron is considered 'active' if the following conditions hold:
818
and patron logged in recently, or placed a hold, article request or borrowed a book recently.
819
A recent enrollment as new patron counts too.
820
818
821
Recently is defined by $date or $value in days, weeks or months. You should
819
    - account did not expire
820
    - account has not been anonymized
821
    - enrollment or lastseen within period specified
822
823
Note: lastseen is updated for triggers defined in preference
824
TrackLastPatronActivityTriggers. This includes logins, issues, holds, etc.
825
826
The period to check is defined by $date or $value in days, weeks or months. You should
822
pass one of those; otherwise an exception is thrown.
827
pass one of those; otherwise an exception is thrown.
823
828
824
=cut
829
=cut
Lines 842-878 sub is_active { Link Here
842
    # Enrollment within this period?
847
    # Enrollment within this period?
843
    return 1 if DateTime->compare( dt_from_string( $self->dateenrolled ), $dt ) > -1;
848
    return 1 if DateTime->compare( dt_from_string( $self->dateenrolled ), $dt ) > -1;
844
849
845
    # Last seen? Updated for tracked patron activities
850
    # We look at lastseen regardless of TrackLastPatronActivityTriggers. If lastseen is set
846
    if ( C4::Context->preference('TrackLastPatronActivityTriggers') ) {
851
    # recently, the triggers may have been removed after that, etc.
847
        return 1 if DateTime->compare( dt_from_string( $self->lastseen ), $dt ) > -1;
852
    return 1 if $self->lastseen && DateTime->compare( dt_from_string( $self->lastseen ), $dt ) > -1;
848
    }
849
850
    # Check holds, issues and article requests
851
    return 1 if $self->holds->filter_by_last_update(
852
        {
853
            timestamp_column_name => 'timestamp', from => $dt,
854
        }
855
    )->count;
856
    return 1 if $self->old_holds->filter_by_last_update(
857
        {
858
            timestamp_column_name => 'timestamp', from => $dt,
859
        }
860
    )->count;
861
    return 1 if $self->checkouts->filter_by_last_update(
862
        {
863
            timestamp_column_name => 'timestamp', from => $dt,
864
        }
865
    )->count;
866
    return 1 if $self->old_checkouts->filter_by_last_update(
867
        {
868
            timestamp_column_name => 'timestamp', from => $dt,
869
        }
870
    )->count;
871
    return 1 if $self->article_requests->filter_by_last_update(
872
        {
873
            timestamp_column_name => 'updated_on', from => $dt,
874
        }
875
    )->count;
876
853
877
    return 0;
854
    return 0;
878
}
855
}
(-)a/t/db_dependent/Koha/Patron.t (-61 / +18 lines)
Lines 322-408 subtest 'Accessor tests' => sub { Link Here
322
};
322
};
323
323
324
subtest 'is_active' => sub {
324
subtest 'is_active' => sub {
325
    plan tests => 19;
325
    plan tests => 12;
326
    $schema->storage->txn_begin;
326
    $schema->storage->txn_begin;
327
327
328
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
328
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
329
    throws_ok { $patron->is_active } 'Koha::Exceptions::MissingParameter', 'Called without params';
329
    throws_ok { $patron->is_active } 'Koha::Exceptions::MissingParameter', 'Called without params';
330
330
331
    # Check expiry
331
    # Check expiry
332
    $patron->dateexpiry( dt_from_string->subtract( days => 1 ) )->store;
332
    $patron->dateexpiry( dt_from_string->subtract( days => 1 ) )->lastseen(undef)->store;
333
    is( $patron->is_active( { days => 1 } ), 0, 'Expired patron is not active' );
333
    is( $patron->is_active( { days => 1 } ), 0, 'Expired patron is not active' );
334
    $patron->dateexpiry(undef)->store;
334
    $patron->dateexpiry(undef)->store;
335
    is( $patron->is_active( { days => 1 } ), 1, 'Expiry date removed' );
335
    is( $patron->is_active( { days => 1 } ), 1, 'Expiry date removed' );
336
336
337
    # Check anonymized
338
    $patron->anonymized(1)->store;
339
    is( $patron->is_active( { days => 1 } ), 0, 'Anonymized patron is not active' );
340
    $patron->anonymized(0)->store;
341
337
    # Change enrolled date now
342
    # Change enrolled date now
338
    $patron->dateenrolled('2020-01-01')->store;
343
    $patron->dateenrolled('2020-01-01')->store;
344
    is( $patron->is_active( { days => 1 } ), 0, 'No recent enrollment and lastseen still empty: not active' );
345
    $patron->dateenrolled( dt_from_string() )->store;
346
    is( $patron->is_active( { days => 1 } ), 1, 'Enrolled today: active' );
339
347
340
    # Check lastseen, test days parameter
348
    # Check lastseen, test days parameter
341
    t::lib::Mocks::mock_preference( 'TrackLastPatronActivityTriggers', 'login' );
349
    t::lib::Mocks::mock_preference( 'TrackLastPatronActivityTriggers', 'login' );
350
    $patron->dateenrolled('2020-01-01')->store;
342
    $patron->update_lastseen('login');
351
    $patron->update_lastseen('login');
343
    is( $patron->is_active( { days => 1 } ), 1, 'Just logged in' );
352
    is( $patron->is_active( { days => 1 } ), 1, 'Just logged in' );
344
    my $ago = dt_from_string->subtract( days => 2 );
353
    my $ago = dt_from_string->subtract( days => 2 );
345
    $patron->lastseen($ago)->store;
354
    $patron->lastseen($ago)->store;
346
    is( $patron->is_active( { days => 1 } ), 0, 'Not active since yesterday' );
355
    is( $patron->is_active( { days => 1 } ), 0, 'Not active since yesterday' );
347
    is( $patron->is_active( { days => 3 } ), 1, 'Active within last 3 days' );
356
    is( $patron->is_active( { days => 3 } ), 1, 'Active within last 3 days' );
348
    t::lib::Mocks::mock_preference( 'TrackLastPatronActivityTriggers', '' );
357
    # test since parameter
349
    is( $patron->is_active( { days => 3 } ), 0, 'Pref disabled' );
358
    my $dt = $ago->clone->add( hours => 1 );
350
359
    is( $patron->is_active( { since => $dt } ), 0, 'Inactive since ago + 1 hour' );
351
    # Look at holds, test with weeks
360
    $dt = $ago->clone->subtract( hours => 1 );
352
    $ago = dt_from_string->subtract( weeks => 2 );
361
    is( $patron->is_active( { since => $dt } ), 1, 'Active since ago - 1 hour' );
353
    my $hold = $builder->build_object(
362
    # test weeks parameter
354
        {
363
    is( $patron->is_active( { weeks => 1 } ), 1, 'Active within last week' );
355
            class => 'Koha::Holds',
356
            value => { borrowernumber => $patron->id, timestamp => $ago },
357
        }
358
    );
359
    is( $patron->is_active( { weeks => 1 } ), 0, 'No holds in 1 weeks' );
360
    is( $patron->is_active( { weeks => 3 } ), 1, 'Hold in last 3 weeks' );
361
    $hold->delete;
362
    my $old_hold = $builder->build_object(
363
        {
364
            class => 'Koha::Old::Holds',
365
            value => { borrowernumber => $patron->id, timestamp => $ago },
366
        }
367
    );
368
    is( $patron->is_active( { weeks => 1 } ), 0, 'No old holds in 1 weeks' );
369
    is( $patron->is_active( { weeks => 3 } ), 1, 'Old hold in last 3 weeks' );
370
    $old_hold->delete;
371
372
    # Look at checkouts, test with months
373
    $ago = dt_from_string->subtract( months => 2 );
374
    my $checkout = $builder->build_object(
375
        {
376
            class => 'Koha::Checkouts',
377
            value => { borrowernumber => $patron->id, timestamp => $ago },
378
        }
379
    );
380
    is( $patron->is_active( { months => 1 } ), 0, 'No checkouts in 1 months' );
381
    is( $patron->is_active( { months => 3 } ), 1, 'Checkout in last 3 months' );
382
    $checkout->delete;
383
    my $old_checkout = $builder->build_object(
384
        {
385
            class => 'Koha::Old::Checkouts',
386
            value => { borrowernumber => $patron->id, timestamp => $ago },
387
        }
388
    );
389
    is( $patron->is_active( { months => 1 } ), 0, 'No old checkouts in 1 months' );
390
    is( $patron->is_active( { months => 3 } ), 1, 'Old checkout in last 3 months' );
391
    $old_checkout->delete;
392
393
    # Look at article_requests, test with since
394
    $ago = dt_from_string->subtract( days => 10 );
395
    my $article_request = $builder->build_object(
396
        {
397
            class => 'Koha::ArticleRequests',
398
            value => { borrowernumber => $patron->id, updated_on => $ago },
399
        }
400
    );
401
    is( $patron->is_active( { days  => 9 } ),                      0, 'No article requests in 9 days' );
402
    is( $patron->is_active( { days  => 10 } ),                     1, 'Article requests in 10 days' );
403
    is( $patron->is_active( { since => $ago } ),                   1, 'Article requests since ago' );
404
    is( $patron->is_active( { since => $ago->add( days => 1 ) } ), 0, 'No article requests since ago + 1 day' );
405
    $article_request->delete;
406
364
407
    $schema->storage->txn_rollback;
365
    $schema->storage->txn_rollback;
408
};
366
};
409
- 

Return to bug 35001