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

(-)a/C4/Circulation.pm (+8 lines)
Lines 909-914 sub CanBookBeIssued { Link Here
909
    }
909
    }
910
910
911
    #
911
    #
912
    # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
913
    #
914
    my $patron = Koha::Patrons->find($borrower->{borrowernumber});
915
    my $wantsCheckPrevCheckout = $patron->wantsCheckPrevCheckout;
916
    $needsconfirmation{PREVISSUE} = 1
917
        if ($wantsCheckPrevCheckout and $patron->doCheckPrevCheckout($item));
918
919
    #
912
    # ITEM CHECKING
920
    # ITEM CHECKING
913
    #
921
    #
914
    if ( $item->{'notforloan'} )
922
    if ( $item->{'notforloan'} )
(-)a/Koha/Patron.pm (+74 lines)
Lines 1-6 Link Here
1
package Koha::Patron;
1
package Koha::Patron;
2
2
3
# Copyright ByWater Solutions 2014
3
# Copyright ByWater Solutions 2014
4
# Copyright PTFS Europe 2016
4
#
5
#
5
# This file is part of Koha.
6
# This file is part of Koha.
6
#
7
#
Lines 21-27 use Modern::Perl; Link Here
21
22
22
use Carp;
23
use Carp;
23
24
25
use C4::Context;
24
use Koha::Database;
26
use Koha::Database;
27
use Koha::Issues;
28
use Koha::OldIssues;
29
use Koha::Patron::Categories;
25
use Koha::Patron::Images;
30
use Koha::Patron::Images;
26
31
27
use base qw(Koha::Object);
32
use base qw(Koha::Object);
Lines 94-99 sub siblings { Link Here
94
    );
99
    );
95
}
100
}
96
101
102
=head3 wantsCheckPrevCheckout
103
104
    $wantsCheckPrevCheckout = $patron->wantsCheckPrevCheckout;
105
106
Return 1 if Koha needs to perform PrevIssue checking, else 0.
107
108
=cut
109
110
sub wantsCheckPrevCheckout {
111
    my ( $self ) = @_;
112
    my $syspref = C4::Context->preference("checkPrevCheckout");
113
114
    # Simple cases
115
    ## Hard syspref trumps all
116
    return 1 if ($syspref eq 'hardyes');
117
    return 0 if ($syspref eq 'hardno');
118
    ## Now, patron pref trumps all
119
    return 1 if ($self->checkprevcheckout eq 'yes');
120
    return 0 if ($self->checkprevcheckout eq 'no');
121
122
    # More complex: patron inherits -> determine category preference
123
    my $checkPrevCheckoutByCat = Koha::Patron::Categories
124
        ->find($self->categorycode)->checkprevcheckout;
125
    return 1 if ($checkPrevCheckoutByCat eq 'yes');
126
    return 0 if ($checkPrevCheckoutByCat eq 'no');
127
128
    # Finally: category preference is inherit, default to 0
129
    if ($syspref eq 'softyes') {
130
        return 1;
131
    } else {
132
        return 0;
133
    }
134
}
135
136
=head3 doCheckPrevCheckout
137
138
    $checkPrevCheckout = $patron->doCheckPrevCheckout($item);
139
140
Return 1 if the bib associated with $ITEM has previously been checked out to
141
$PATRON, 0 otherwise.
142
143
=cut
144
145
sub doCheckPrevCheckout {
146
    my ( $self, $item ) = @_;
147
148
    # Find all items for bib and extract item numbers.
149
    my @items = Koha::Items->search({biblionumber => $item->{biblionumber}});
150
    my @item_nos;
151
    foreach my $item (@items) {
152
        push @item_nos, $item->itemnumber;
153
    }
154
155
    # Create (old)issues search criteria
156
    my $criteria = {
157
        borrowernumber => $self->borrowernumber,
158
        itemnumber => \@item_nos,
159
    };
160
161
    # Check current issues table
162
    my $issues = Koha::Issues->search($criteria);
163
    return 1 if $issues->count; # 0 || N
164
165
    # Check old issues table
166
    my $old_issues = Koha::OldIssues->search($criteria);
167
    return $old_issues->count;  # 0 || N
168
}
169
97
=head3 type
170
=head3 type
98
171
99
=cut
172
=cut
Lines 105-110 sub _type { Link Here
105
=head1 AUTHOR
178
=head1 AUTHOR
106
179
107
Kyle M Hall <kyle@bywatersolutions.com>
180
Kyle M Hall <kyle@bywatersolutions.com>
181
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
108
182
109
=cut
183
=cut
110
184
(-)a/admin/categories.pl (+3 lines)
Lines 90-95 elsif ( $op eq 'add_validate' ) { Link Here
90
    my $overduenoticerequired = $input->param('overduenoticerequired');
90
    my $overduenoticerequired = $input->param('overduenoticerequired');
91
    my $category_type = $input->param('category_type');
91
    my $category_type = $input->param('category_type');
92
    my $BlockExpiredPatronOpacActions = $input->param('BlockExpiredPatronOpacActions');
92
    my $BlockExpiredPatronOpacActions = $input->param('BlockExpiredPatronOpacActions');
93
    my $checkPrevCheckout = $input->param('checkprevcheckout');
93
    my $default_privacy = $input->param('default_privacy');
94
    my $default_privacy = $input->param('default_privacy');
94
    my @branches = grep { $_ ne q{} } $input->param('branches');
95
    my @branches = grep { $_ ne q{} } $input->param('branches');
95
96
Lines 113-118 elsif ( $op eq 'add_validate' ) { Link Here
113
        $category->overduenoticerequired($overduenoticerequired);
114
        $category->overduenoticerequired($overduenoticerequired);
114
        $category->category_type($category_type);
115
        $category->category_type($category_type);
115
        $category->BlockExpiredPatronOpacActions($BlockExpiredPatronOpacActions);
116
        $category->BlockExpiredPatronOpacActions($BlockExpiredPatronOpacActions);
117
        $category->checkprevcheckout($checkPrevCheckout);
116
        $category->default_privacy($default_privacy);
118
        $category->default_privacy($default_privacy);
117
        eval {
119
        eval {
118
            $category->store;
120
            $category->store;
Lines 138-143 elsif ( $op eq 'add_validate' ) { Link Here
138
            overduenoticerequired => $overduenoticerequired,
140
            overduenoticerequired => $overduenoticerequired,
139
            category_type => $category_type,
141
            category_type => $category_type,
140
            BlockExpiredPatronOpacActions => $BlockExpiredPatronOpacActions,
142
            BlockExpiredPatronOpacActions => $BlockExpiredPatronOpacActions,
143
            checkprevcheckout => $checkPrevCheckout,
141
            default_privacy => $default_privacy,
144
            default_privacy => $default_privacy,
142
        });
145
        });
143
        eval {
146
        eval {
(-)a/installer/data/mysql/atomicupdate/checkPrevCheckout.sql (+15 lines)
Line 0 Link Here
1
INSERT INTO systempreferences (variable,value,options,explanation,type)
2
VALUES('CheckPrevCheckout','hardno','hardyes|softyes|softno|hardno','By default, for every item checked out, should we warn if the patron has checked out that item in the past?','Choice');
3
4
ALTER TABLE categories
5
ADD COLUMN `checkprevcheckout` varchar(7) NOT NULL default 'inherit'
6
AFTER `default_privacy`;
7
8
ALTER TABLE borrowers
9
ADD COLUMN `checkprevcheckout` varchar(7) NOT NULL default 'inherit'
10
AFTER `privacy_guarantor_checkouts`;
11
12
ALTER TABLE deletedborrowers
13
ADD COLUMN `checkprevcheckout` varchar(7) NOT NULL default 'inherit'
14
AFTER `privacy_guarantor_checkouts`;
15
(-)a/installer/data/mysql/kohastructure.sql (+3 lines)
Lines 266-271 CREATE TABLE `borrowers` ( -- this table includes information about your patrons Link Here
266
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
266
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
267
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history
267
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history
268
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
268
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
269
  `checkprevcheckout` varchar(7) NOT NULL default 'inherit', -- produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'.
269
  UNIQUE KEY `cardnumber` (`cardnumber`),
270
  UNIQUE KEY `cardnumber` (`cardnumber`),
270
  PRIMARY KEY `borrowernumber` (`borrowernumber`),
271
  PRIMARY KEY `borrowernumber` (`borrowernumber`),
271
  KEY `categorycode` (`categorycode`),
272
  KEY `categorycode` (`categorycode`),
Lines 505-510 CREATE TABLE `categories` ( -- this table shows information related to Koha patr Link Here
505
  `category_type` varchar(1) NOT NULL default 'A', -- type of Koha patron (Adult, Child, Professional, Organizational, Statistical, Staff)
506
  `category_type` varchar(1) NOT NULL default 'A', -- type of Koha patron (Adult, Child, Professional, Organizational, Statistical, Staff)
506
  `BlockExpiredPatronOpacActions` tinyint(1) NOT NULL default '-1', -- wheither or not a patron of this category can renew books or place holds once their card has expired. 0 means they can, 1 means they cannot, -1 means use syspref BlockExpiredPatronOpacActions
507
  `BlockExpiredPatronOpacActions` tinyint(1) NOT NULL default '-1', -- wheither or not a patron of this category can renew books or place holds once their card has expired. 0 means they can, 1 means they cannot, -1 means use syspref BlockExpiredPatronOpacActions
507
  `default_privacy` ENUM( 'default', 'never', 'forever' ) NOT NULL DEFAULT 'default', -- Default privacy setting for this patron category
508
  `default_privacy` ENUM( 'default', 'never', 'forever' ) NOT NULL DEFAULT 'default', -- Default privacy setting for this patron category
509
  `checkprevcheckout` varchar(7) NOT NULL default 'inherit', -- produce a warning for this patron category if this item has previously been checked out to this patron if 'yes', not if 'no', defer to syspref setting if 'inherit'.
508
  PRIMARY KEY  (`categorycode`),
510
  PRIMARY KEY  (`categorycode`),
509
  UNIQUE KEY `categorycode` (`categorycode`)
511
  UNIQUE KEY `categorycode` (`categorycode`)
510
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
512
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Lines 918-923 CREATE TABLE `deletedborrowers` ( -- stores data related to the patrons/borrower Link Here
918
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
920
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
919
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history  KEY `borrowernumber` (`borrowernumber`),
921
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history  KEY `borrowernumber` (`borrowernumber`),
920
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
922
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
923
  `checkprevcheckout` varchar(7) NOT NULL default 'inherit', -- produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'.
921
  KEY borrowernumber (borrowernumber),
924
  KEY borrowernumber (borrowernumber),
922
  KEY `cardnumber` (`cardnumber`),
925
  KEY `cardnumber` (`cardnumber`),
923
  KEY `sms_provider_id` (`sms_provider_id`)
926
  KEY `sms_provider_id` (`sms_provider_id`)
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 90-95 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
90
('CatalogModuleRelink','0',NULL,'If OFF the linker will never replace the authids that are set in the cataloging module.','YesNo'),
90
('CatalogModuleRelink','0',NULL,'If OFF the linker will never replace the authids that are set in the cataloging module.','YesNo'),
91
('CataloguingLog','1',NULL,'If ON, log edit/create/delete actions on bibliographic data. WARNING: this feature is very resource consuming.','YesNo'),
91
('CataloguingLog','1',NULL,'If ON, log edit/create/delete actions on bibliographic data. WARNING: this feature is very resource consuming.','YesNo'),
92
('checkdigit','none','none|katipo','If ON, enable checks on patron cardnumber: none or \"Katipo\" style checks','Choice'),
92
('checkdigit','none','none|katipo','If ON, enable checks on patron cardnumber: none or \"Katipo\" style checks','Choice'),
93
('CheckPrevCheckout','hardno','hardyes|softyes|softno|hardno','By default, for every item checked out, should we warn if the patron has borrowed that item in the past?','Choice'),
93
('CircAutocompl','1',NULL,'If ON, autocompletion is enabled for the Circulation input','YesNo'),
94
('CircAutocompl','1',NULL,'If ON, autocompletion is enabled for the Circulation input','YesNo'),
94
('CircAutoPrintQuickSlip','qslip',NULL,'Choose what should happen when an empty barcode field is submitted in circulation: Display a print quick slip window, Display a print slip window or Clear the screen.','Choice'),
95
('CircAutoPrintQuickSlip','qslip',NULL,'Choose what should happen when an empty barcode field is submitted in circulation: Display a print quick slip window, Display a print slip window or Clear the screen.','Choice'),
95
('CircControl','ItemHomeLibrary','PickupLibrary|PatronLibrary|ItemHomeLibrary','Specify the agency that controls the circulation and fines policy','Choice'),
96
('CircControl','ItemHomeLibrary','PickupLibrary|PatronLibrary|ItemHomeLibrary','Specify the agency that controls the circulation and fines policy','Choice'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt (+53 lines)
Lines 276-281 Link Here
276
                        Choose whether patrons of this category be blocked from public catalog actions such as renewing and placing holds when their cards have expired.
276
                        Choose whether patrons of this category be blocked from public catalog actions such as renewing and placing holds when their cards have expired.
277
                    </span>
277
                    </span>
278
                </li>
278
                </li>
279
                [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' )  %]
280
                  <li><label for="checkprevcheckout">Check for previous checkouts: </label>
281
                      <select name="checkprevcheckout" id="checkprevcheckout">
282
                          [% IF category.checkprevcheckout == 'yes' %]
283
                          <option value="yes" selected="selected">Yes and try to override system preferences</option>
284
                          <option value="no">No and try to override system preferences</option>
285
                          <option value="inherit">Inherit from system preferences</option>
286
                          [% ELSIF category.checkprevcheckout == 'no' %]
287
                          <option value="yes">Yes and try to override system preferences</option>
288
                          <option value="no" selected="selected">No and try to override system preferences</option>
289
                          <option value="inherit">Inherit from system preferences</option>
290
                          [% ELSE %]
291
                          <option value="yes">Yes and try to override system preferences</option>
292
                          <option value="no">No and try to override system preferences</option>
293
                          <option value="inherit" selected="selected">Inherit from system preferences</option>
294
                          [% END %]
295
                      </select>
296
                      <span>
297
                          Choose whether patrons of this category by default are reminded if they try to borrow an item they borrowed before.
298
                      </span>
299
                  </li>
300
                [% END %]
279
                <li>
301
                <li>
280
                    <label for="default_privacy">Default privacy: </label>
302
                    <label for="default_privacy">Default privacy: </label>
281
                    <select id="default_privacy" name="default_privacy">
303
                    <select id="default_privacy" name="default_privacy">
Lines 345-350 Link Here
345
                <tr><th scope="row">Receives overdue notices: </th><td>[% IF category. overduenoticerequired %]Yes[% ELSE %]No[% END %]</td></tr>
367
                <tr><th scope="row">Receives overdue notices: </th><td>[% IF category. overduenoticerequired %]Yes[% ELSE %]No[% END %]</td></tr>
346
                <tr><th scope="row">Lost items in staff client</th><td>[% IF category.hidelostitems %]Hidden by default[% ELSE %]Shown[% END %]</td></tr>
368
                <tr><th scope="row">Lost items in staff client</th><td>[% IF category.hidelostitems %]Hidden by default[% ELSE %]Shown[% END %]</td></tr>
347
                <tr><th scope="row">Hold fee: </th><td>[% category.reservefee | $Price %]</td></tr>
369
                <tr><th scope="row">Hold fee: </th><td>[% category.reservefee | $Price %]</td></tr>
370
371
                [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
372
                  <tr>
373
                      <th scope="row">Check previous checkouts: </th>
374
                      <td>
375
                          [% SWITCH category.checkprevcheckout %]
376
                          [% CASE 'yes' %]
377
                              Yes
378
                          [% CASE 'no' %]
379
                              No
380
                          [% CASE 'inherit' %]
381
                              Inherit
382
                          [% END %]
383
                      </td>
384
                  </tr>
385
                [% END %]
348
                <tr>
386
                <tr>
349
                    <th scope="row">Default privacy: </th>
387
                    <th scope="row">Default privacy: </th>
350
                    <td>
388
                    <td>
Lines 401-406 Link Here
401
                    <th scope="col">Messaging</th>
439
                    <th scope="col">Messaging</th>
402
                    [% END %]
440
                    [% END %]
403
                    <th scope="col">Branches limitations</th>
441
                    <th scope="col">Branches limitations</th>
442
                    [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
443
                    <th scope="col">Check previous checkout?</th>
444
                    [% END %]
404
                    <th scope="col">Default privacy</th>
445
                    <th scope="col">Default privacy</th>
405
                    <th scope="col">&nbsp; </th>
446
                    <th scope="col">&nbsp; </th>
406
                    <th scope="col">&nbsp; </th>
447
                    <th scope="col">&nbsp; </th>
Lines 478-483 Link Here
478
                                No limitation
519
                                No limitation
479
                            [% END %]
520
                            [% END %]
480
                        </td>
521
                        </td>
522
                        [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
523
                          <td>
524
                              [% SWITCH category.checkprevcheckout %]
525
                              [% CASE 'yes' %]
526
                              Yes
527
                              [% CASE 'no' %]
528
                              No
529
                              [% CASE 'inherit' %]
530
                              Inherit
531
                              [% END %]
532
                          </td>
533
                        [% END %]
481
                        <td>
534
                        <td>
482
                            [% SWITCH category.default_privacy %]
535
                            [% SWITCH category.default_privacy %]
483
                            [% CASE 'default' %]
536
                            [% CASE 'default' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref (+9 lines)
Lines 44-49 Patrons: Link Here
44
           class: multi
44
           class: multi
45
         - (separate multiple choices with |)
45
         - (separate multiple choices with |)
46
     -
46
     -
47
         - pref: CheckPrevCheckout
48
           default: no
49
           choices:
50
               hardyes: "Do"
51
               softyes: "Unless overridden, do"
52
               softno: "Unless overridden, do not"
53
               hardno: "Do not"
54
         - " check borrower checkout history to see if the current item has been checked out before."
55
     -
47
         - pref: checkdigit
56
         - pref: checkdigit
48
           choices:
57
           choices:
49
               none: "Don't"
58
               none: "Don't"
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+4 lines)
Lines 308-313 $(document).ready(function() { Link Here
308
    <li>High demand item. Loan period shortened to [% HIGHHOLDS.duration %] days (due [% HIGHHOLDS.returndate %]). Check out anyway?</li>
308
    <li>High demand item. Loan period shortened to [% HIGHHOLDS.duration %] days (due [% HIGHHOLDS.returndate %]). Check out anyway?</li>
309
[% END %]
309
[% END %]
310
310
311
[% IF PREVISSUE %]
312
    <li>This item has previously been checked out to this patron.  Check out anyway?</li>
313
[% END %]
314
311
[% IF BIBLIO_ALREADY_ISSUED %]
315
[% IF BIBLIO_ALREADY_ISSUED %]
312
  <li>
316
  <li>
313
    Patron has already checked out another item from this record.
317
    Patron has already checked out another item from this record.
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt (-1 / +20 lines)
Lines 737-743 function select_user(borrowernumber, borrower) { Link Here
737
            [% END %]
737
            [% END %]
738
        </li>
738
        </li>
739
    [% END %]
739
    [% END %]
740
	</ol>
740
    [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
741
      <li><label for="checkprevcheckout">Check for previous checkouts: </label>
742
        <select name="checkprevcheckout" id="checkprevcheckout">
743
        [% IF ( checkprevcheckout == 'yes' ) %]
744
          <option value="yes" selected="selected">Yes if settings allow it</option>
745
          <option value="no">No if settings allow it</option>
746
          <option value="inherit">Inherit from settings</option>
747
        [% ELSIF ( checkprevcheckout == 'no' ) %]
748
          <option value="yes">Yes if settings allow it</option>
749
          <option value="no" selected="selected">No if settings allow it</option>
750
          <option value="inherit">Inherit from settings</option>
751
        [% ELSE %]
752
          <option value="yes">Yes if settings allow it</option>
753
          <option value="no">No if settings allow it</option>
754
          <option value="inherit" selected="selected">Inherit from settings</option>
755
        [% END %]
756
        </select>
757
       </li>
758
     [% END %]
759
   </ol>
741
  </fieldset>
760
  </fieldset>
742
    [% UNLESS nodateenrolled &&  noopacnote && noborrowernotes %]
761
    [% UNLESS nodateenrolled &&  noopacnote && noborrowernotes %]
743
	<fieldset class="rows" id="memberentry_subscription">
762
	<fieldset class="rows" id="memberentry_subscription">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (+11 lines)
Lines 400-405 function validate1(date) { Link Here
400
            <li><span class="label">Activate sync: </span>No</li>
400
            <li><span class="label">Activate sync: </span>No</li>
401
        [% END %]
401
        [% END %]
402
    [% END %]
402
    [% END %]
403
    [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
404
      <li><span class="label">Check previous checkouts: </span>
405
        [% IF ( checkprevcheckout == 'yes' ) %]
406
        Yes
407
        [% ELSIF ( checkprevcheckout == 'no' ) %]
408
        No
409
        [% ELSE %]
410
        Inherited
411
        [% END %]
412
      </li>
413
    [% END %]
403
	</ol>
414
	</ol>
404
	</div>
415
	</div>
405
 </div>
416
 </div>
(-)a/t/db_dependent/Patron/CheckPrevCheckout.t (-1 / +447 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
use Modern::Perl;
3
4
use C4::Members;
5
use C4::Circulation;
6
use Koha::Database;
7
use Koha::Patrons;
8
use Koha::Patron;
9
10
use Test::More tests => 59;
11
12
use_ok('Koha::Patron');
13
14
use t::lib::TestBuilder;
15
use t::lib::Mocks;
16
17
my $schema = Koha::Database->new->schema;
18
$schema->storage->txn_begin;
19
20
my $builder = t::lib::TestBuilder->new;
21
my $yesCatCode = $builder->build({
22
    source => 'Category',
23
    value => {
24
        categorycode => 'yesCat',
25
        checkprevcheckout => 'yes',
26
    },
27
});
28
29
my $noCatCode = $builder->build({
30
    source => 'Category',
31
    value => {
32
        categorycode => 'noCat',
33
        checkprevcheckout => 'no',
34
    },
35
});
36
37
my $inheritCatCode = $builder->build({
38
    source => 'Category',
39
    value => {
40
        categorycode => 'inheritCat',
41
        checkprevcheckout => 'inherit',
42
    },
43
});
44
45
# Create context for some tests late on in the file.
46
my $staff = $builder->build({source => 'Borrower'});
47
my @USERENV = (
48
    $staff->{borrowernumber}, 'test', 'MASTERTEST', 'firstname', 'CPL',
49
    'CPL', 'email@example.org'
50
);
51
C4::Context->_new_userenv('DUMMY_SESSION_ID');
52
C4::Context->set_userenv(@USERENV);
53
BAIL_OUT("No userenv") unless C4::Context->userenv;
54
55
56
# wantsCheckPrevCheckout
57
58
# We expect the following result matrix:
59
#
60
# (1/0 indicates the return value of WantsCheckPrevCheckout; i.e. 1 says we
61
# should check whether the item was previously issued)
62
#
63
# | System Preference | hardyes                           | softyes                           | softno                            | hardno                            |
64
# |-------------------+-----------------------------------+-----------------------------------+-----------------------------------+-----------------------------------|
65
# | Category Setting  | yes       | no        | inherit   | yes       | no        | inherit   | yes       | no        | inherit   | yes       | no        | inherit   |
66
# |-------------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------|
67
# | Patron Setting    | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i | y | n | i |
68
# |-------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
69
# | Expected Result   | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
70
71
my $mappings = [
72
    {
73
        syspref    => 'hardyes',
74
        categories => [
75
            {
76
                setting => 'yes',
77
                patrons => [
78
                    {setting => 'yes',     result => 1},
79
                    {setting => 'no',      result => 1},
80
                    {setting => 'inherit', result => 1},
81
                ],
82
            },
83
            {
84
                setting => 'no',
85
                patrons => [
86
                    {setting => 'yes',     result => 1},
87
                    {setting => 'no',      result => 1},
88
                    {setting => 'inherit', result => 1},
89
                ],
90
            },
91
            {
92
                setting => 'inherit',
93
                patrons => [
94
                    {setting => 'yes',     result => 1},
95
                    {setting => 'no',      result => 1},
96
                    {setting => 'inherit', result => 1},
97
                ],
98
            },
99
        ],
100
    },
101
    {
102
        syspref    => 'softyes',
103
        categories => [
104
            {
105
                setting => 'yes',
106
                patrons => [
107
                    {setting => 'yes',     result => 1},
108
                    {setting => 'no',      result => 0},
109
                    {setting => 'inherit', result => 1},
110
                ],
111
            },
112
            {
113
                setting => 'no',
114
                patrons => [
115
                    {setting => 'yes',     result => 1},
116
                    {setting => 'no',      result => 0},
117
                    {setting => 'inherit', result => 0},
118
                ],
119
            },
120
            {
121
                setting => 'inherit',
122
                patrons => [
123
                    {setting => 'yes',     result => 1},
124
                    {setting => 'no',      result => 0},
125
                    {setting => 'inherit', result => 1},
126
                ],
127
            },
128
        ],
129
    },
130
    {
131
        syspref    => 'softno',
132
        categories => [
133
            {
134
                setting => 'yes',
135
                patrons => [
136
                    {setting => 'yes',     result => 1},
137
                    {setting => 'no',      result => 0},
138
                    {setting => 'inherit', result => 1},
139
                ],
140
            },
141
            {
142
                setting => 'no',
143
                patrons => [
144
                    {setting => 'yes',     result => 1},
145
                    {setting => 'no',      result => 0},
146
                    {setting => 'inherit', result => 0},
147
                ],
148
            },
149
            {
150
                setting => 'inherit',
151
                patrons => [
152
                    {setting => 'yes',     result => 1},
153
                    {setting => 'no',      result => 0},
154
                    {setting => 'inherit', result => 0},
155
                ],
156
            },
157
        ],
158
    },
159
    {
160
        syspref    => 'hardno',
161
        categories => [
162
            {
163
                setting => 'yes',
164
                patrons => [
165
                    {setting => 'yes',     result => 0},
166
                    {setting => 'no',      result => 0},
167
                    {setting => 'inherit', result => 0},
168
                ],
169
            },
170
            {
171
                setting => 'no',
172
                patrons => [
173
                    {setting => 'yes',     result => 0},
174
                    {setting => 'no',      result => 0},
175
                    {setting => 'inherit', result => 0},
176
                ],
177
            },
178
            {
179
                setting => 'inherit',
180
                patrons => [
181
                    {setting => 'yes',     result => 0},
182
                    {setting => 'no',      result => 0},
183
                    {setting => 'inherit', result => 0},
184
                ],
185
            },
186
        ],
187
    },
188
];
189
190
map {
191
    my $syspref = $_->{syspref};
192
    t::lib::Mocks::mock_preference('checkprevcheckout', $syspref);
193
    map {
194
        my $code = $_->{setting} . 'Cat';
195
        map {
196
            my $kpatron = $builder->build({
197
                source => 'Borrower',
198
                value  => {
199
                    checkprevcheckout => $_->{setting},
200
                    categorycode => $code,
201
                },
202
            });
203
            my $patron = Koha::Patrons->find($kpatron->{borrowernumber});
204
            is(
205
                $patron->wantsCheckPrevCheckout, $_->{result},
206
                "Predicate with syspref " . $syspref . ", cat " . $code
207
                    . ", patron " . $_->{setting}
208
              );
209
        } @{$_->{patrons}};
210
    } @{$_->{categories}};
211
} @{$mappings};
212
213
# doCheckPrevCheckout
214
215
# We want to test:
216
# - DESCRIPTION [RETURNVALUE (0/1)]
217
## PreIssue (sanity checks)
218
# - Item, patron [0]
219
# - Diff item, same bib, same patron [0]
220
# - Diff item, diff bib, same patron [0]
221
# - Same item, diff patron [0]
222
# - Diff item, same bib, diff patron [0]
223
# - Diff item, diff bib, diff patron [0]
224
## PostIssue
225
# - Same item, same patron [1]
226
# - Diff item, same bib, same patron [1]
227
# - Diff item, diff bib, same patron [0]
228
# - Same item, diff patron [0]
229
# - Diff item, same bib, diff patron [0]
230
# - Diff item, diff bib, diff patron [0]
231
## PostReturn
232
# - Same item, same patron [1]
233
# - Diff item, same bib, same patron [1]
234
# - Diff item, diff bib, same patron [0]
235
# - Same item, diff patron [0]
236
# - Diff item, same bib, diff patron [0]
237
# - Diff item, diff bib, diff patron [0]
238
239
# Requirements:
240
# $patron, $different_patron, $items (same bib number), $different_item
241
my $patron = $builder->build({source => 'Borrower'});
242
my $patron_d = $builder->build({source => 'Borrower'});
243
my $item_1 = $builder->build({source => 'Item'});
244
my $item_2 = $builder->build({
245
    source => 'Item',
246
    value => { biblionumber => $item_1->{biblionumber} },
247
});
248
my $item_d = $builder->build({source => 'Item'});
249
250
## Testing Sub
251
sub test_it {
252
    my ($mapping, $stage) = @_;
253
    map {
254
        my $patron = Koha::Patrons->find($_->{patron}->{borrowernumber});
255
        is(
256
            $patron->doCheckPrevCheckout($_->{item}),
257
            $_->{result}, $stage . ": " . $_->{msg}
258
        );
259
    } @{$mapping};
260
};
261
262
## Initial Mappings
263
my $cpvmappings = [
264
    {
265
        msg => "Item, patron [0]",
266
        item => $item_1,
267
        patron => $patron,
268
        result => 0,
269
    },
270
    {
271
        msg => "Diff item, same bib, same patron [0]",
272
        item => $item_2,
273
        patron => $patron,
274
        result => 0,
275
    },
276
    {
277
        msg => "Diff item, diff bib, same patron [0]",
278
        item => $item_d,
279
        patron => $patron,
280
        result => 0,
281
    },
282
    {
283
        msg => "Same item, diff patron [0]",
284
        item => $item_1,
285
        patron => $patron_d,
286
        result => 0,
287
    },
288
    {
289
        msg => "Diff item, same bib, diff patron [0]",
290
        item => $item_2,
291
        patron => $patron_d,
292
        result => 0,
293
    },
294
    {
295
        msg => "Diff item, diff bib, diff patron [0]",
296
        item => $item_d,
297
        patron => $patron_d,
298
        result => 0,
299
    },
300
];
301
302
test_it($cpvmappings, "PreIssue");
303
304
# Issue item_1 to $patron:
305
my $patron_get_mem =
306
    GetMember(%{{borrowernumber => $patron->{borrowernumber}}});
307
BAIL_OUT("Issue failed")
308
    unless AddIssue($patron_get_mem, $item_1->{barcode});
309
310
# Then test:
311
my $cpvPmappings = [
312
    {
313
        msg => "Same item, same patron [1]",
314
        item => $item_1,
315
        patron => $patron,
316
        result => 1,
317
    },
318
    {
319
        msg => "Diff item, same bib, same patron [1]",
320
        item => $item_2,
321
        patron => $patron,
322
        result => 1,
323
    },
324
    {
325
        msg => "Diff item, diff bib, same patron [0]",
326
        item => $item_d,
327
        patron => $patron,
328
        result => 0,
329
    },
330
    {
331
        msg => "Same item, diff patron [0]",
332
        item => $item_1,
333
        patron => $patron_d,
334
        result => 0,
335
    },
336
    {
337
        msg => "Diff item, same bib, diff patron [0]",
338
        item => $item_2,
339
        patron => $patron_d,
340
        result => 0,
341
    },
342
    {
343
        msg => "Diff item, diff bib, diff patron [0]",
344
        item => $item_d,
345
        patron => $patron_d,
346
        result => 0,
347
    },
348
];
349
350
test_it($cpvPmappings, "PostIssue");
351
352
# Return item_1 from patron:
353
BAIL_OUT("Return Failed") unless AddReturn($item_1->{barcode}, $patron->{branchcode});
354
355
# Then:
356
test_it($cpvPmappings, "PostReturn");
357
358
# Finally test C4::Circulation::CanBookBeIssued
359
360
# We have already tested ->wantsCheckPrevCheckout and ->doCheckPrevCheckout,
361
# so all that remains to be tested is whetherthe different combinational
362
# outcomes of the above return values in CanBookBeIssued result in the
363
# approriate $needsconfirmation.
364
365
# We want to test:
366
# - DESCRIPTION [RETURNVALUE (0/1)]
367
# - patron, !wantsCheckPrevCheckout, !doCheckPrevCheckout
368
#   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
369
# - patron, wantsCheckPrevCheckout, !doCheckPrevCheckout
370
#   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
371
# - patron, !wantsCheckPrevCheckout, doCheckPrevCheckout
372
#   [!$issuingimpossible,!$needsconfirmation->{PREVISSUE}]
373
# - patron, wantsCheckPrevCheckout, doCheckPrevCheckout
374
#   [!$issuingimpossible,$needsconfirmation->{PREVISSUE}]
375
376
# Needs:
377
# - $patron_from_GetMember
378
# - $item objects (one not issued, another prevIssued)
379
# - $checkprevcheckout pref (first hardno, then hardyes)
380
381
# Our Patron
382
my $CBBI_patron = $builder->build({source => 'Borrower'});
383
my $p_from_GetMember =
384
    GetMember(%{{borrowernumber => $CBBI_patron->{borrowernumber}}});
385
# Our Items
386
my $new_item = $builder->build({
387
    source => 'Item',
388
    value => {
389
        notforloan => 0,
390
        withdrawn  => 0,
391
        itemlost   => 0,
392
    },
393
});
394
my $prev_item = $builder->build({
395
    source => 'Item',
396
    value => {
397
        notforloan => 0,
398
        withdrawn  => 0,
399
        itemlost   => 0,
400
    },
401
});
402
# Second is Checked Out
403
BAIL_OUT("CanBookBeIssued Issue failed")
404
    unless AddIssue($p_from_GetMember, $prev_item->{barcode});
405
406
# Mappings
407
my $CBBI_mappings = [
408
    {
409
        syspref => 'hardno',
410
        item    => $new_item,
411
        result  => undef,
412
        msg     => "patron, !wantsCheckPrevCheckout, !doCheckPrevCheckout"
413
414
    },
415
    {
416
        syspref => 'hardyes',
417
        item    => $new_item,
418
        result  => undef,
419
        msg     => "patron, wantsCheckPrevCheckout, !doCheckPrevCheckout"
420
    },
421
    {
422
        syspref => 'hardno',
423
        item    => $prev_item,
424
        result  => undef,
425
        msg     => "patron, !wantsCheckPrevCheckout, doCheckPrevCheckout"
426
    },
427
    {
428
        syspref => 'hardyes',
429
        item    => $prev_item,
430
        result  => 1,
431
        msg     => "patron, wantsCheckPrevCheckout, doCheckPrevCheckout"
432
    },
433
];
434
435
# Tests
436
map {
437
    t::lib::Mocks::mock_preference('checkprevcheckout', $_->{syspref});
438
    my ( $issuingimpossible, $needsconfirmation ) =
439
        C4::Circulation::CanBookBeIssued(
440
            $p_from_GetMember, $_->{item}->{barcode}
441
        );
442
    is($needsconfirmation->{PREVISSUE}, $_->{result}, $_->{msg});
443
} @{$CBBI_mappings};
444
445
$schema->storage->txn_rollback;
446
447
1;

Return to bug 6906