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

(-)a/C4/Circulation.pm (+8 lines)
Lines 47-52 use Algorithm::CheckDigits; Link Here
47
use Data::Dumper;
47
use Data::Dumper;
48
use Koha::DateUtils;
48
use Koha::DateUtils;
49
use Koha::Calendar;
49
use Koha::Calendar;
50
use Koha::Items;
51
use Koha::Borrowers;
50
use Koha::Borrower::Debarments;
52
use Koha::Borrower::Debarments;
51
use Koha::Database;
53
use Koha::Database;
52
use Carp;
54
use Carp;
Lines 2178-2183 sub MarkIssueReturned { Link Here
2178
    $sth_del->execute($borrowernumber, $itemnumber);
2180
    $sth_del->execute($borrowernumber, $itemnumber);
2179
2181
2180
    ModItem( { 'onloan' => undef }, undef, $itemnumber );
2182
    ModItem( { 'onloan' => undef }, undef, $itemnumber );
2183
2184
    if ( C4::Context->preference('StoreLastBorrower') ) {
2185
        my $item = Koha::Items->find( $itemnumber );
2186
        my $patron = Koha::Borrowers->find( $borrowernumber );
2187
        $item->last_returned_by( $patron );
2188
    }
2181
}
2189
}
2182
2190
2183
=head2 _debar_user_on_return
2191
=head2 _debar_user_on_return
(-)a/Koha/Item.pm (+33 lines)
Lines 24-29 use Carp; Link Here
24
use Koha::Database;
24
use Koha::Database;
25
25
26
use Koha::Branches;
26
use Koha::Branches;
27
use Koha::Borrowers;
27
28
28
use base qw(Koha::Object);
29
use base qw(Koha::Object);
29
30
Lines 73-78 sub holding_branch { Link Here
73
    return $self->{_holding_branch};
74
    return $self->{_holding_branch};
74
}
75
}
75
76
77
=head3 last_returned_by
78
79
Gets and sets the last borrower to return an item.
80
81
Accepts and returns Koha::Borrower objects
82
83
$item->last_returned_by( $borrowernumber );
84
85
$last_returned_by = $item->last_returned_by();
86
87
=cut
88
89
sub last_returned_by {
90
    my ( $self, $borrower ) = @_;
91
92
    my $items_last_returned_by_rs = Koha::Database->new()->schema()->resultset('ItemsLastBorrower');
93
94
    if ($borrower) {
95
        return $items_last_returned_by_rs->update_or_create(
96
            { borrowernumber => $borrower->borrowernumber, itemnumber => $self->id } );
97
    }
98
    else {
99
        unless ( $self->{_last_returned_by} ) {
100
            my $result = $items_last_returned_by_rs->single( { itemnumber => $self->id } );
101
            if ($result) {
102
                $self->{_last_returned_by} = Koha::Borrowers->find( $result->get_column('borrowernumber') );
103
            }
104
        }
105
106
        return $self->{_last_returned_by};
107
    }
108
}
76
109
77
=head3 type
110
=head3 type
78
111
(-)a/Koha/Schema/Result/ItemsLastBorrower.pm (+133 lines)
Line 0 Link Here
1
use utf8;
2
package Koha::Schema::Result::ItemsLastBorrower;
3
4
# Created by DBIx::Class::Schema::Loader
5
# DO NOT MODIFY THE FIRST PART OF THIS FILE
6
7
=head1 NAME
8
9
Koha::Schema::Result::ItemsLastBorrower
10
11
=cut
12
13
use strict;
14
use warnings;
15
16
use base 'DBIx::Class::Core';
17
18
=head1 TABLE: C<items_last_borrower>
19
20
=cut
21
22
__PACKAGE__->table("items_last_borrower");
23
24
=head1 ACCESSORS
25
26
=head2 id
27
28
  data_type: 'integer'
29
  is_auto_increment: 1
30
  is_nullable: 0
31
32
=head2 itemnumber
33
34
  data_type: 'integer'
35
  is_foreign_key: 1
36
  is_nullable: 0
37
38
=head2 borrowernumber
39
40
  data_type: 'integer'
41
  is_foreign_key: 1
42
  is_nullable: 0
43
44
=head2 created_on
45
46
  data_type: 'timestamp'
47
  datetime_undef_if_invalid: 1
48
  default_value: current_timestamp
49
  is_nullable: 0
50
51
=cut
52
53
__PACKAGE__->add_columns(
54
  "id",
55
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
56
  "itemnumber",
57
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
58
  "borrowernumber",
59
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
60
  "created_on",
61
  {
62
    data_type => "timestamp",
63
    datetime_undef_if_invalid => 1,
64
    default_value => \"current_timestamp",
65
    is_nullable => 0,
66
  },
67
);
68
69
=head1 PRIMARY KEY
70
71
=over 4
72
73
=item * L</id>
74
75
=back
76
77
=cut
78
79
__PACKAGE__->set_primary_key("id");
80
81
=head1 UNIQUE CONSTRAINTS
82
83
=head2 C<itemnumber>
84
85
=over 4
86
87
=item * L</itemnumber>
88
89
=back
90
91
=cut
92
93
__PACKAGE__->add_unique_constraint("itemnumber", ["itemnumber"]);
94
95
=head1 RELATIONS
96
97
=head2 borrowernumber
98
99
Type: belongs_to
100
101
Related object: L<Koha::Schema::Result::Borrower>
102
103
=cut
104
105
__PACKAGE__->belongs_to(
106
  "borrowernumber",
107
  "Koha::Schema::Result::Borrower",
108
  { borrowernumber => "borrowernumber" },
109
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
110
);
111
112
=head2 itemnumber
113
114
Type: belongs_to
115
116
Related object: L<Koha::Schema::Result::Item>
117
118
=cut
119
120
__PACKAGE__->belongs_to(
121
  "itemnumber",
122
  "Koha::Schema::Result::Item",
123
  { itemnumber => "itemnumber" },
124
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
125
);
126
127
128
# Created by DBIx::Class::Schema::Loader v0.07040 @ 2015-10-02 12:33:33
129
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ByHKNZCEz4a1AqTnOJgUWA
130
131
132
# You can replace this text with custom code or comments, and it will be preserved on regeneration
133
1;
(-)a/catalogue/moredetail.pl (+2 lines)
Lines 38-43 use C4::Reserves qw(GetReservesFromBiblionumber); Link Here
38
38
39
use Koha::Acquisition::Bookseller;
39
use Koha::Acquisition::Bookseller;
40
use Koha::DateUtils;
40
use Koha::DateUtils;
41
use Koha::Items;
41
42
42
my $query=new CGI;
43
my $query=new CGI;
43
44
Lines 135-140 foreach ( keys %{$data} ) { Link Here
135
136
136
($itemnumber) and @items = (grep {$_->{'itemnumber'} == $itemnumber} @items);
137
($itemnumber) and @items = (grep {$_->{'itemnumber'} == $itemnumber} @items);
137
foreach my $item (@items){
138
foreach my $item (@items){
139
    $item->{object} = Koha::Items->find( $item->{itemnumber} );
138
    $item->{itemlostloop}= GetAuthorisedValues(GetAuthValCode('items.itemlost',$fw),$item->{itemlost}) if GetAuthValCode('items.itemlost',$fw);
140
    $item->{itemlostloop}= GetAuthorisedValues(GetAuthValCode('items.itemlost',$fw),$item->{itemlost}) if GetAuthValCode('items.itemlost',$fw);
139
    $item->{itemdamagedloop}= GetAuthorisedValues(GetAuthValCode('items.damaged',$fw),$item->{damaged}) if GetAuthValCode('items.damaged',$fw);
141
    $item->{itemdamagedloop}= GetAuthorisedValues(GetAuthValCode('items.damaged',$fw),$item->{damaged}) if GetAuthValCode('items.damaged',$fw);
140
    $item->{'collection'}              = $ccodes->{ $item->{ccode} } if ($ccodes);
142
    $item->{'collection'}              = $ccodes->{ $item->{ccode} } if ($ccodes);
(-)a/installer/data/mysql/atomicupdate/bug_14945.sql (+13 lines)
Line 0 Link Here
1
INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('StoreLastBorrower','0','','If ON, the last borrower to return an item will be stored in items.last_returned_by','YesNo');
2
3
CREATE TABLE IF NOT EXISTS `items_last_borrower` (
4
  `id` int(11) NOT NULL AUTO_INCREMENT,
5
  `itemnumber` int(11) NOT NULL,
6
  `borrowernumber` int(11) NOT NULL,
7
  `created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
8
  PRIMARY KEY (`id`),
9
  UNIQUE KEY `itemnumber` (`itemnumber`),
10
  KEY `borrowernumber` (`borrowernumber`),
11
  CONSTRAINT `items_last_borrower_ibfk_2` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE CASCADE ON UPDATE CASCADE,
12
  CONSTRAINT `items_last_borrower_ibfk_1` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE CASCADE ON UPDATE CASCADE
13
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
(-)a/installer/data/mysql/kohastructure.sql (+16 lines)
Lines 1262-1267 CREATE TABLE `items` ( -- holdings/item information Link Here
1262
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1262
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1263
1263
1264
--
1264
--
1265
-- Table structure for table `items_last_borrower`
1266
--
1267
1268
CREATE TABLE IF NOT EXISTS `items_last_borrower` (
1269
  `id` int(11) NOT NULL AUTO_INCREMENT,
1270
  `itemnumber` int(11) NOT NULL,
1271
  `borrowernumber` int(11) NOT NULL,
1272
  `created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
1273
  PRIMARY KEY (`id`),
1274
  UNIQUE KEY `itemnumber` (`itemnumber`),
1275
  KEY `borrowernumber` (`borrowernumber`),
1276
  CONSTRAINT `items_last_borrower_ibfk_2` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`) ON DELETE CASCADE ON UPDATE CASCADE,
1277
  CONSTRAINT `items_last_borrower_ibfk_1` FOREIGN KEY (`itemnumber`) REFERENCES `items` (`itemnumber`) ON DELETE CASCADE ON UPDATE CASCADE
1278
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1279
1280
--
1265
-- Table structure for table `itemtypes`
1281
-- Table structure for table `itemtypes`
1266
--
1282
--
1267
1283
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 424-429 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
424
('StaffSerialIssueDisplayCount','3','','Number of serial issues to display per subscription in the Staff client','Integer'),
424
('StaffSerialIssueDisplayCount','3','','Number of serial issues to display per subscription in the Staff client','Integer'),
425
('StaticHoldsQueueWeight','0',NULL,'Specify a list of library location codes separated by commas -- the list of codes will be traversed and weighted with first values given higher weight for holds fulfillment -- alternatively, if RandomizeHoldsQueueWeight is set, the list will be randomly selective','Integer'),
425
('StaticHoldsQueueWeight','0',NULL,'Specify a list of library location codes separated by commas -- the list of codes will be traversed and weighted with first values given higher weight for holds fulfillment -- alternatively, if RandomizeHoldsQueueWeight is set, the list will be randomly selective','Integer'),
426
('StatisticsFields','location|itype|ccode', NULL, 'Define Fields (from the items table) used for statistics members','Free'),
426
('StatisticsFields','location|itype|ccode', NULL, 'Define Fields (from the items table) used for statistics members','Free'),
427
('StoreLastBorrower','0','','If ON, the last borrower to return an item will be stored in items.last_returned_by','YesNo'),
427
('SubfieldsToAllowForRestrictedBatchmod','','Define a list of subfields for which edition is authorized when items_batchmod_restricted permission is enabled, separated by spaces. Example: 995\$f 995\$h 995\$j',NULL,'Free'),
428
('SubfieldsToAllowForRestrictedBatchmod','','Define a list of subfields for which edition is authorized when items_batchmod_restricted permission is enabled, separated by spaces. Example: 995\$f 995\$h 995\$j',NULL,'Free'),
428
('SubfieldsToAllowForRestrictedEditing','','Define a list of subfields for which edition is authorized when edit_items_restricted permission is enabled, separated by spaces. Example: 995\$f 995\$h 995\$j',NULL,'Free'),
429
('SubfieldsToAllowForRestrictedEditing','','Define a list of subfields for which edition is authorized when edit_items_restricted permission is enabled, separated by spaces. Example: 995\$f 995\$h 995\$j',NULL,'Free'),
429
('SubfieldsToUseWhenPrefill','','','Define a list of subfields to use when prefilling items (separated by space)','Free'),
430
('SubfieldsToUseWhenPrefill','','','Define a list of subfields to use when prefilling items (separated by space)','Free'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref (-1 / +7 lines)
Lines 563-568 OPAC: Link Here
563
563
564
    Privacy:
564
    Privacy:
565
        -
565
        -
566
            - pref: StoreLastBorrower
567
              default: 0
568
              choices:
569
                  yes: Store
570
                  no: "Don't store"
571
            - the last patron to return an item. This setting is independent of opacreadinghistory/AnonymousPatron.
572
        -
566
            - pref: AnonSuggestions
573
            - pref: AnonSuggestions
567
              choices:
574
              choices:
568
                  yes: Allow
575
                  yes: Allow
Lines 616-622 OPAC: Link Here
616
            - pref: RestrictedPageTitle
623
            - pref: RestrictedPageTitle
617
              class: long
624
              class: long
618
            - "as title of your restricted page (appears in the breadcrumb and on the top of the restricted page)"
625
            - "as title of your restricted page (appears in the breadcrumb and on the top of the restricted page)"
619
620
    Shelf Browser:
626
    Shelf Browser:
621
        -
627
        -
622
            - pref: OPACShelfBrowser
628
            - pref: OPACShelfBrowser
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt (+4 lines)
Lines 1-3 Link Here
1
[% USE Koha %]
1
[% INCLUDE 'doc-head-open.inc' %]
2
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Catalog &rsaquo; Item details for [% title %] [% FOREACH subtitl IN subtitle %] [% subtitl.subfield %][% END %]</title>
3
<title>Koha &rsaquo; Catalog &rsaquo; Item details for [% title %] [% FOREACH subtitl IN subtitle %] [% subtitl.subfield %][% END %]</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
[% INCLUDE 'doc-head-close.inc' %]
Lines 216-221 Link Here
216
217
217
                <li><span class="label">Last seen:</span>[% IF ( ITEM_DAT.datelastseen ) %][% ITEM_DAT.datelastseen | $KohaDates %] [%END %]&nbsp;</li>
218
                <li><span class="label">Last seen:</span>[% IF ( ITEM_DAT.datelastseen ) %][% ITEM_DAT.datelastseen | $KohaDates %] [%END %]&nbsp;</li>
218
                <li><span class="label">Last borrowed:</span>[% IF (ITEM_DAT.datelastborrowed ) %][% ITEM_DAT.datelastborrowed | $KohaDates %][% END %]&nbsp;</li>
219
                <li><span class="label">Last borrowed:</span>[% IF (ITEM_DAT.datelastborrowed ) %][% ITEM_DAT.datelastborrowed | $KohaDates %][% END %]&nbsp;</li>
220
                [% IF Koha.Preference('StoreLastBorrower') && ITEM_DAT.object.last_returned_by %]
221
                    <li><span class="label">Last returned by:</span> <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% ITEM_DAT.object.last_returned_by.borrowernumber %]">[% ITEM_DAT.object.last_returned_by.cardnumber %]</a>&nbsp;</li>
222
                [% END %]
219
                [% IF ( ITEM_DAT.card0 ) %]<li><span class="label">Last borrower:</span> <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% ITEM_DAT.borrower0 %]">[% ITEM_DAT.card0 %]</a>&nbsp;</li>[% END %]
223
                [% IF ( ITEM_DAT.card0 ) %]<li><span class="label">Last borrower:</span> <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% ITEM_DAT.borrower0 %]">[% ITEM_DAT.card0 %]</a>&nbsp;</li>[% END %]
220
                [% IF ( ITEM_DAT.card1 ) %]<li><span class="label">Previous borrower:</span> <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% ITEM_DAT.borrower1 %]">[% ITEM_DAT.card1 %]</a>&nbsp;</li>[% END %]
224
                [% IF ( ITEM_DAT.card1 ) %]<li><span class="label">Previous borrower:</span> <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% ITEM_DAT.borrower1 %]">[% ITEM_DAT.card1 %]</a>&nbsp;</li>[% END %]
221
                [% IF ( ITEM_DAT.card2 ) %]<li><span class="label">Previous borrower:</span> <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% ITEM_DAT.borrower2 %]">[% ITEM_DAT.card2 %]</a>&nbsp;</li>[% END %]
225
                [% IF ( ITEM_DAT.card2 ) %]<li><span class="label">Previous borrower:</span> <a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% ITEM_DAT.borrower2 %]">[% ITEM_DAT.card2 %]</a>&nbsp;</li>[% END %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-privacy.tt (+1 lines)
Lines 77-82 Link Here
77
                            <p>Whatever your privacy rule you choose, you can delete all your reading history immediately by clicking here. <b>BE CAREFUL</b>. Once you've confirmed the deletion, no one can retrieve the list!</p>
77
                            <p>Whatever your privacy rule you choose, you can delete all your reading history immediately by clicking here. <b>BE CAREFUL</b>. Once you've confirmed the deletion, no one can retrieve the list!</p>
78
                            <input type="submit" value="Immediate deletion" class="btn btn-danger" onclick="return confirmDelete(MSG_CONFIRM_AGAIN);" />
78
                            <input type="submit" value="Immediate deletion" class="btn btn-danger" onclick="return confirmDelete(MSG_CONFIRM_AGAIN);" />
79
                        </form>
79
                        </form>
80
                        [% IF Koha.Preference('StoreLastBorrower') %]<p id="store-last-borrower-msg">Please note, the last person to return an item is tracked for the management of items returned damaged.</p>[% END %]
80
                    [% END # / IF Ask_data %]
81
                    [% END # / IF Ask_data %]
81
                </div> <!-- / .userprivacy -->
82
                </div> <!-- / .userprivacy -->
82
            </div> <!-- / .span10 -->
83
            </div> <!-- / .span10 -->
(-)a/t/db_dependent/Circulation/AnonymiseIssueHistory.t (-2 / +83 lines)
Lines 18-28 Link Here
18
18
19
use Modern::Perl;
19
use Modern::Perl;
20
20
21
use Test::More tests => 3;
21
use Test::More tests => 4;
22
22
23
use C4::Context;
23
use C4::Context;
24
use C4::Circulation;
24
use C4::Circulation;
25
25
use Koha::Database;
26
use Koha::Database;
27
use Koha::Items;
26
28
27
use t::lib::Mocks;
29
use t::lib::Mocks;
28
use t::lib::TestBuilder;
30
use t::lib::TestBuilder;
Lines 161-166 subtest 'AnonymousPatron is not defined' => sub { Link Here
161
    is( $borrowernumber_used_to_anonymised, undef, 'With AnonymousPatron is not defined, the issue should have been anonymised anyway' );
163
    is( $borrowernumber_used_to_anonymised, undef, 'With AnonymousPatron is not defined, the issue should have been anonymised anyway' );
162
};
164
};
163
165
166
subtest 'Test StoreLastBorrower' => sub {
167
    plan tests => 4;
168
169
    t::lib::Mocks::mock_preference( 'StoreLastBorrower', '1' );
170
171
    my $patron = $builder->build(
172
        {
173
            source => 'Borrower',
174
            value  => { privacy => 1, }
175
        }
176
    );
177
178
    my $item = $builder->build(
179
        {
180
            source => 'Item',
181
            value  => {
182
                itemlost  => 0,
183
                withdrawn => 0,
184
            },
185
        }
186
    );
187
188
    my $issue = $builder->build(
189
        {
190
            source => 'Issue',
191
            value  => {
192
                borrowernumber => $patron->{borrowernumber},
193
                itemnumber     => $item->{itemnumber},
194
            },
195
        }
196
    );
197
198
    my $item_object   = Koha::Items->find( $item->{itemnumber} );
199
    my $patron_object = $item_object->last_returned_by();
200
    is( $patron_object, undef, 'Koha::Item::last_returned_by returned undef' );
201
202
    my ( $returned, undef, undef ) = C4::Circulation::AddReturn( $item->{barcode}, undef, undef, undef, '2010-10-10' );
203
204
    $item_object   = Koha::Items->find( $item->{itemnumber} );
205
    $patron_object = $item_object->last_returned_by();
206
    is( ref($patron_object), 'Koha::Borrower', 'Koha::Item::last_returned_by returned Koha::Borrower' );
207
208
    $patron = $builder->build(
209
        {
210
            source => 'Borrower',
211
            value  => { privacy => 1, }
212
        }
213
    );
214
215
    $issue = $builder->build(
216
        {
217
            source => 'Issue',
218
            value  => {
219
                borrowernumber => $patron->{borrowernumber},
220
                itemnumber     => $item->{itemnumber},
221
            },
222
        }
223
    );
224
225
    ( $returned, undef, undef ) = C4::Circulation::AddReturn( $item->{barcode}, undef, undef, undef, '2010-10-10' );
226
227
    $item_object   = Koha::Items->find( $item->{itemnumber} );
228
    $patron_object = $item_object->last_returned_by();
229
    is( $patron_object->id, $patron->{borrowernumber}, 'Second patron to return item replaces the first' );
230
231
    $patron = $builder->build(
232
        {
233
            source => 'Borrower',
234
            value  => { privacy => 1, }
235
        }
236
    );
237
    $patron_object = Koha::Borrowers->find( $patron->{borrowernumber} );
238
239
    $item_object->last_returned_by($patron_object);
240
    $item_object = Koha::Items->find( $item->{itemnumber} );
241
    my $patron_object2 = $item_object->last_returned_by();
242
    is( $patron_object->id, $patron_object2->id,
243
        'Calling last_returned_by with Borrower object sets last_returned_by to that borrower' );
244
};
245
164
$schema->storage->txn_rollback;
246
$schema->storage->txn_rollback;
165
247
166
1;
248
1;
167
- 

Return to bug 14945