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

(-)a/C4/Circulation.pm (+8 lines)
Lines 941-946 sub CanBookBeIssued { Link Here
941
    }
941
    }
942
942
943
    #
943
    #
944
    # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
945
    #
946
    my $patron = Koha::Patrons->find($borrower->{borrowernumber});
947
    my $wantsCheckPrevCheckout = $patron->wantsCheckPrevCheckout;
948
    $needsconfirmation{PREVISSUE} = 1
949
        if ($wantsCheckPrevCheckout and $patron->doCheckPrevCheckout($item));
950
951
    #
944
    # ITEM CHECKING
952
    # ITEM CHECKING
945
    #
953
    #
946
    if ( $item->{'notforloan'} )
954
    if ( $item->{'notforloan'} )
(-)a/Koha/Patron.pm (-1 / +75 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-29 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;
25
use Koha::Patrons;
27
use Koha::Issues;
28
use Koha::OldIssues;
29
use Koha::Patron::Categories;
26
use Koha::Patron::Images;
30
use Koha::Patron::Images;
31
use Koha::Patrons;
27
32
28
use base qw(Koha::Object);
33
use base qw(Koha::Object);
29
34
Lines 95-100 sub siblings { Link Here
95
    );
100
    );
96
}
101
}
97
102
103
=head3 wantsCheckPrevCheckout
104
105
    $wantsCheckPrevCheckout = $patron->wantsCheckPrevCheckout;
106
107
Return 1 if Koha needs to perform PrevIssue checking, else 0.
108
109
=cut
110
111
sub wantsCheckPrevCheckout {
112
    my ( $self ) = @_;
113
    my $syspref = C4::Context->preference("checkPrevCheckout");
114
115
    # Simple cases
116
    ## Hard syspref trumps all
117
    return 1 if ($syspref eq 'hardyes');
118
    return 0 if ($syspref eq 'hardno');
119
    ## Now, patron pref trumps all
120
    return 1 if ($self->checkprevcheckout eq 'yes');
121
    return 0 if ($self->checkprevcheckout eq 'no');
122
123
    # More complex: patron inherits -> determine category preference
124
    my $checkPrevCheckoutByCat = Koha::Patron::Categories
125
        ->find($self->categorycode)->checkprevcheckout;
126
    return 1 if ($checkPrevCheckoutByCat eq 'yes');
127
    return 0 if ($checkPrevCheckoutByCat eq 'no');
128
129
    # Finally: category preference is inherit, default to 0
130
    if ($syspref eq 'softyes') {
131
        return 1;
132
    } else {
133
        return 0;
134
    }
135
}
136
137
=head3 doCheckPrevCheckout
138
139
    $checkPrevCheckout = $patron->doCheckPrevCheckout($item);
140
141
Return 1 if the bib associated with $ITEM has previously been checked out to
142
$PATRON, 0 otherwise.
143
144
=cut
145
146
sub doCheckPrevCheckout {
147
    my ( $self, $item ) = @_;
148
149
    # Find all items for bib and extract item numbers.
150
    my @items = Koha::Items->search({biblionumber => $item->{biblionumber}});
151
    my @item_nos;
152
    foreach my $item (@items) {
153
        push @item_nos, $item->itemnumber;
154
    }
155
156
    # Create (old)issues search criteria
157
    my $criteria = {
158
        borrowernumber => $self->borrowernumber,
159
        itemnumber => \@item_nos,
160
    };
161
162
    # Check current issues table
163
    my $issues = Koha::Issues->search($criteria);
164
    return 1 if $issues->count; # 0 || N
165
166
    # Check old issues table
167
    my $old_issues = Koha::OldIssues->search($criteria);
168
    return $old_issues->count;  # 0 || N
169
}
170
98
=head3 type
171
=head3 type
99
172
100
=cut
173
=cut
Lines 106-111 sub _type { Link Here
106
=head1 AUTHOR
179
=head1 AUTHOR
107
180
108
Kyle M Hall <kyle@bywatersolutions.com>
181
Kyle M Hall <kyle@bywatersolutions.com>
182
Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>
109
183
110
=cut
184
=cut
111
185
(-)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->multi_param('branches');
95
    my @branches = grep { $_ ne q{} } $input->multi_param('branches');
95
96
Lines 119-124 elsif ( $op eq 'add_validate' ) { Link Here
119
        $category->overduenoticerequired($overduenoticerequired);
120
        $category->overduenoticerequired($overduenoticerequired);
120
        $category->category_type($category_type);
121
        $category->category_type($category_type);
121
        $category->BlockExpiredPatronOpacActions($BlockExpiredPatronOpacActions);
122
        $category->BlockExpiredPatronOpacActions($BlockExpiredPatronOpacActions);
123
        $category->checkprevcheckout($checkPrevCheckout);
122
        $category->default_privacy($default_privacy);
124
        $category->default_privacy($default_privacy);
123
        eval {
125
        eval {
124
            $category->store;
126
            $category->store;
Lines 144-149 elsif ( $op eq 'add_validate' ) { Link Here
144
            overduenoticerequired => $overduenoticerequired,
146
            overduenoticerequired => $overduenoticerequired,
145
            category_type => $category_type,
147
            category_type => $category_type,
146
            BlockExpiredPatronOpacActions => $BlockExpiredPatronOpacActions,
148
            BlockExpiredPatronOpacActions => $BlockExpiredPatronOpacActions,
149
            checkprevcheckout => $checkPrevCheckout,
147
            default_privacy => $default_privacy,
150
            default_privacy => $default_privacy,
148
        });
151
        });
149
        eval {
152
        eval {
(-)a/installer/data/mysql/atomicupdate/checkPrevCheckout.sql (+14 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`;
(-)a/installer/data/mysql/kohastructure.sql (+3 lines)
Lines 319-324 CREATE TABLE `categories` ( -- this table shows information related to Koha patr Link Here
319
  `category_type` varchar(1) NOT NULL default 'A', -- type of Koha patron (Adult, Child, Professional, Organizational, Statistical, Staff)
319
  `category_type` varchar(1) NOT NULL default 'A', -- type of Koha patron (Adult, Child, Professional, Organizational, Statistical, Staff)
320
  `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
320
  `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
321
  `default_privacy` ENUM( 'default', 'never', 'forever' ) NOT NULL DEFAULT 'default', -- Default privacy setting for this patron category
321
  `default_privacy` ENUM( 'default', 'never', 'forever' ) NOT NULL DEFAULT 'default', -- Default privacy setting for this patron category
322
  `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'.
322
  PRIMARY KEY  (`categorycode`),
323
  PRIMARY KEY  (`categorycode`),
323
  UNIQUE KEY `categorycode` (`categorycode`)
324
  UNIQUE KEY `categorycode` (`categorycode`)
324
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
325
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Lines 618-623 CREATE TABLE `deletedborrowers` ( -- stores data related to the patrons/borrower Link Here
618
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
619
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
619
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history  KEY `borrowernumber` (`borrowernumber`),
620
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history  KEY `borrowernumber` (`borrowernumber`),
620
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
621
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
622
  `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'.
621
  `updated_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- time of last change could be useful for synchronization with external systems (among others)
623
  `updated_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- time of last change could be useful for synchronization with external systems (among others)
622
  KEY borrowernumber (borrowernumber),
624
  KEY borrowernumber (borrowernumber),
623
  KEY `cardnumber` (`cardnumber`),
625
  KEY `cardnumber` (`cardnumber`),
Lines 1624-1629 CREATE TABLE `borrowers` ( -- this table includes information about your patrons Link Here
1624
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
1626
  `sms_provider_id` int(11) DEFAULT NULL, -- the provider of the mobile phone number defined in smsalertnumber
1625
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history
1627
  `privacy` integer(11) DEFAULT '1' NOT NULL, -- patron/borrower's privacy settings related to their reading history
1626
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
1628
  `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT '0', -- controls if relatives can see this patron's checkouts
1629
  `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'.
1627
  `updated_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- time of last change could be useful for synchronization with external systems (among others)
1630
  `updated_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- time of last change could be useful for synchronization with external systems (among others)
1628
  UNIQUE KEY `cardnumber` (`cardnumber`),
1631
  UNIQUE KEY `cardnumber` (`cardnumber`),
1629
  PRIMARY KEY `borrowernumber` (`borrowernumber`),
1632
  PRIMARY KEY `borrowernumber` (`borrowernumber`),
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 91-96 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
91
('CatalogModuleRelink','0',NULL,'If OFF the linker will never replace the authids that are set in the cataloging module.','YesNo'),
91
('CatalogModuleRelink','0',NULL,'If OFF the linker will never replace the authids that are set in the cataloging module.','YesNo'),
92
('CataloguingLog','1',NULL,'If ON, log edit/create/delete actions on bibliographic data. WARNING: this feature is very resource consuming.','YesNo'),
92
('CataloguingLog','1',NULL,'If ON, log edit/create/delete actions on bibliographic data. WARNING: this feature is very resource consuming.','YesNo'),
93
('checkdigit','none','none|katipo','If ON, enable checks on patron cardnumber: none or \"Katipo\" style checks','Choice'),
93
('checkdigit','none','none|katipo','If ON, enable checks on patron cardnumber: none or \"Katipo\" style checks','Choice'),
94
('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'),
94
('CircAutocompl','1',NULL,'If ON, autocompletion is enabled for the Circulation input','YesNo'),
95
('CircAutocompl','1',NULL,'If ON, autocompletion is enabled for the Circulation input','YesNo'),
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'),
96
('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'),
96
('CircControl','ItemHomeLibrary','PickupLibrary|PatronLibrary|ItemHomeLibrary','Specify the agency that controls the circulation and fines policy','Choice'),
97
('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 189-194 Link Here
189
                        Choose whether patrons of this category be blocked from public catalog actions such as renewing and placing holds when their cards have expired.
189
                        Choose whether patrons of this category be blocked from public catalog actions such as renewing and placing holds when their cards have expired.
190
                    </span>
190
                    </span>
191
                </li>
191
                </li>
192
                [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' )  %]
193
                  <li><label for="checkprevcheckout">Check for previous checkouts: </label>
194
                      <select name="checkprevcheckout" id="checkprevcheckout">
195
                          [% IF category.checkprevcheckout == 'yes' %]
196
                          <option value="yes" selected="selected">Yes and try to override system preferences</option>
197
                          <option value="no">No and try to override system preferences</option>
198
                          <option value="inherit">Inherit from system preferences</option>
199
                          [% ELSIF category.checkprevcheckout == 'no' %]
200
                          <option value="yes">Yes and try to override system preferences</option>
201
                          <option value="no" selected="selected">No and try to override system preferences</option>
202
                          <option value="inherit">Inherit from system preferences</option>
203
                          [% ELSE %]
204
                          <option value="yes">Yes and try to override system preferences</option>
205
                          <option value="no">No and try to override system preferences</option>
206
                          <option value="inherit" selected="selected">Inherit from system preferences</option>
207
                          [% END %]
208
                      </select>
209
                      <span>
210
                          Choose whether patrons of this category by default are reminded if they try to borrow an item they borrowed before.
211
                      </span>
212
                  </li>
213
                [% END %]
192
                <li>
214
                <li>
193
                    <label for="default_privacy">Default privacy: </label>
215
                    <label for="default_privacy">Default privacy: </label>
194
                    <select id="default_privacy" name="default_privacy">
216
                    <select id="default_privacy" name="default_privacy">
Lines 261-266 Link Here
261
                <tr><th scope="row">Receives overdue notices: </th><td>[% IF category. overduenoticerequired %]Yes[% ELSE %]No[% END %]</td></tr>
283
                <tr><th scope="row">Receives overdue notices: </th><td>[% IF category. overduenoticerequired %]Yes[% ELSE %]No[% END %]</td></tr>
262
                <tr><th scope="row">Lost items in staff client</th><td>[% IF category.hidelostitems %]Hidden by default[% ELSE %]Shown[% END %]</td></tr>
284
                <tr><th scope="row">Lost items in staff client</th><td>[% IF category.hidelostitems %]Hidden by default[% ELSE %]Shown[% END %]</td></tr>
263
                <tr><th scope="row">Hold fee: </th><td>[% category.reservefee | $Price %]</td></tr>
285
                <tr><th scope="row">Hold fee: </th><td>[% category.reservefee | $Price %]</td></tr>
286
287
                [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
288
                  <tr>
289
                      <th scope="row">Check previous checkouts: </th>
290
                      <td>
291
                          [% SWITCH category.checkprevcheckout %]
292
                          [% CASE 'yes' %]
293
                              Yes
294
                          [% CASE 'no' %]
295
                              No
296
                          [% CASE 'inherit' %]
297
                              Inherit
298
                          [% END %]
299
                      </td>
300
                  </tr>
301
                [% END %]
264
                <tr>
302
                <tr>
265
                    <th scope="row">Default privacy: </th>
303
                    <th scope="row">Default privacy: </th>
266
                    <td>
304
                    <td>
Lines 317-322 Link Here
317
                    <th scope="col">Messaging</th>
355
                    <th scope="col">Messaging</th>
318
                    [% END %]
356
                    [% END %]
319
                    <th scope="col">Branches limitations</th>
357
                    <th scope="col">Branches limitations</th>
358
                    [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
359
                    <th scope="col">Check previous checkout?</th>
360
                    [% END %]
320
                    <th scope="col">Default privacy</th>
361
                    <th scope="col">Default privacy</th>
321
                    <th scope="col">&nbsp; </th>
362
                    <th scope="col">&nbsp; </th>
322
                    <th scope="col">&nbsp; </th>
363
                    <th scope="col">&nbsp; </th>
Lines 394-399 Link Here
394
                                No limitation
435
                                No limitation
395
                            [% END %]
436
                            [% END %]
396
                        </td>
437
                        </td>
438
                        [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
439
                          <td>
440
                              [% SWITCH category.checkprevcheckout %]
441
                              [% CASE 'yes' %]
442
                              Yes
443
                              [% CASE 'no' %]
444
                              No
445
                              [% CASE 'inherit' %]
446
                              Inherit
447
                              [% END %]
448
                          </td>
449
                        [% END %]
397
                        <td>
450
                        <td>
398
                            [% SWITCH category.default_privacy %]
451
                            [% SWITCH category.default_privacy %]
399
                            [% CASE 'default' %]
452
                            [% 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 264-269 $(document).ready(function() { Link Here
264
    <li>High demand item. Loan period shortened to [% HIGHHOLDS.duration %] days (due [% HIGHHOLDS.returndate %]). Check out anyway?</li>
264
    <li>High demand item. Loan period shortened to [% HIGHHOLDS.duration %] days (due [% HIGHHOLDS.returndate %]). Check out anyway?</li>
265
[% END %]
265
[% END %]
266
266
267
[% IF PREVISSUE %]
268
    <li>This item has previously been checked out to this patron.  Check out anyway?</li>
269
[% END %]
270
267
[% IF BIBLIO_ALREADY_ISSUED %]
271
[% IF BIBLIO_ALREADY_ISSUED %]
268
  <li>
272
  <li>
269
    Patron has already checked out another item from this record.
273
    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 636-642 $(document).ready(function() { Link Here
636
            [% END %]
636
            [% END %]
637
        </li>
637
        </li>
638
    [% END %]
638
    [% END %]
639
	</ol>
639
    [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
640
      <li><label for="checkprevcheckout">Check for previous checkouts: </label>
641
        <select name="checkprevcheckout" id="checkprevcheckout">
642
        [% IF ( checkprevcheckout == 'yes' ) %]
643
          <option value="yes" selected="selected">Yes if settings allow it</option>
644
          <option value="no">No if settings allow it</option>
645
          <option value="inherit">Inherit from settings</option>
646
        [% ELSIF ( checkprevcheckout == 'no' ) %]
647
          <option value="yes">Yes if settings allow it</option>
648
          <option value="no" selected="selected">No if settings allow it</option>
649
          <option value="inherit">Inherit from settings</option>
650
        [% ELSE %]
651
          <option value="yes">Yes if settings allow it</option>
652
          <option value="no">No if settings allow it</option>
653
          <option value="inherit" selected="selected">Inherit from settings</option>
654
        [% END %]
655
        </select>
656
       </li>
657
     [% END %]
658
   </ol>
640
  </fieldset>
659
  </fieldset>
641
    [% UNLESS nodateenrolled &&  noopacnote && noborrowernotes %]
660
    [% UNLESS nodateenrolled &&  noopacnote && noborrowernotes %]
642
	<fieldset class="rows" id="memberentry_subscription">
661
	<fieldset class="rows" id="memberentry_subscription">
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (+11 lines)
Lines 406-411 function validate1(date) { Link Here
406
            <li><span class="label">Activate sync: </span>No</li>
406
            <li><span class="label">Activate sync: </span>No</li>
407
        [% END %]
407
        [% END %]
408
    [% END %]
408
    [% END %]
409
    [% IF ( Koha.Preference('CheckPrevCheckout') == 'softyes' || Koha.Preference('CheckPrevCheckout') == 'softno' ) %]
410
      <li><span class="label">Check previous checkouts: </span>
411
        [% IF ( checkprevcheckout == 'yes' ) %]
412
        Yes
413
        [% ELSIF ( checkprevcheckout == 'no' ) %]
414
        No
415
        [% ELSE %]
416
        Inherited
417
        [% END %]
418
      </li>
419
    [% END %]
409
	</ol>
420
	</ol>
410
	</div>
421
	</div>
411
 </div>
422
 </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