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

(-)a/Koha/Schema/Result/Reserve.pm (+12 lines)
Lines 376-379 sub koha_objects_class { Link Here
376
    'Koha::Holds';
376
    'Koha::Holds';
377
}
377
}
378
378
379
__PACKAGE__->belongs_to(
380
  "itembib",
381
  "Koha::Schema::Result::Item",
382
  { biblionumber => "biblionumber" },
383
  {
384
    is_deferrable => 1,
385
    join_type     => "LEFT",
386
    on_delete     => "CASCADE",
387
    on_update     => "CASCADE",
388
  },
389
);
390
379
1;
391
1;
(-)a/circ/pendingreserves.pl (-114 / +113 lines)
Lines 149-283 unless ( $enddate ) { Link Here
149
    $enddate = $today + DateTime::Duration->new( days => C4::Context->preference('ConfirmFutureHolds') || 0 );
149
    $enddate = $today + DateTime::Duration->new( days => C4::Context->preference('ConfirmFutureHolds') || 0 );
150
}
150
}
151
151
152
my @reservedata;
152
# building query parameters
153
my $dbh = C4::Context->dbh;
153
my %where = (
154
my $sqldatewhere = "";
154
    'reserve.found' => undef,
155
    'reserve.suspend' => 0,
156
    'itembib.itemlost' => 0,
157
    'itembib.withdrawn' => 0,
158
    'itembib.notforloan' => 0,
159
    'itembib.itemnumber' => { -not_in => \'SELECT itemnumber FROM branchtransfers WHERE datearrived IS NULL' }
160
);
161
162
# date boundaries
155
my $startdate_iso = output_pref({ dt => $startdate, dateformat => 'iso', dateonly => 1 });
163
my $startdate_iso = output_pref({ dt => $startdate, dateformat => 'iso', dateonly => 1 });
156
my $enddate_iso   = output_pref({ dt => $enddate, dateformat => 'iso', dateonly => 1 });
164
my $enddate_iso   = output_pref({ dt => $enddate, dateformat => 'iso', dateonly => 1 });
157
165
if ( $startdate_iso && $enddate_iso ){
158
$debug and warn $startdate_iso. "\n" . $enddate_iso;
166
    $where{'reserve.reservedate'} = [ -and => { '>=', $startdate_iso }, { '<=', $enddate_iso } ];
159
167
} elsif ( $startdate_iso ){
160
my @query_params = ();
168
    $where{'reserve.reservedate'} = { '>=', $startdate_iso };
161
169
} elsif ( $enddate_iso ){
162
if ($startdate_iso) {
170
    $where{'reserve.reservedate'} = { '<=', $enddate_iso };
163
    $sqldatewhere .= " AND reservedate >= ?";
164
    push @query_params, $startdate_iso;
165
}
166
if ($enddate_iso) {
167
    $sqldatewhere .= " AND reservedate <= ?";
168
    push @query_params, $enddate_iso;
169
}
171
}
170
172
171
my $item_type = C4::Context->preference('item-level_itypes') ? "items.itype" : "biblioitems.itemtype";
172
173
# Bug 21320
173
# Bug 21320
174
if ( ! C4::Context->preference('AllowHoldsOnDamagedItems') ) {
174
if ( !C4::Context->preference('AllowHoldsOnDamagedItems') ){
175
    $sqldatewhere .= " AND damaged = 0";
175
    $where{'itembib.damaged'} = 0;
176
}
176
}
177
177
178
my $strsth =
178
if ( C4::Context->preference('IndependentBranches') ){
179
    "SELECT min(reservedate) as l_reservedate,
179
    $where{'itembib.holdingbranch'} = C4::Context->userenv->{'branch'};
180
            reserves.reserve_id,
181
            reserves.borrowernumber as borrowernumber,
182
183
            GROUP_CONCAT(DISTINCT items.holdingbranch 
184
                    ORDER BY items.itemnumber SEPARATOR '|') l_holdingbranch,
185
            reserves.biblionumber,
186
            reserves.branchcode as l_branch,
187
            reserves.itemnumber,
188
            items.holdingbranch,
189
            items.homebranch,
190
            GROUP_CONCAT(DISTINCT $item_type
191
                    ORDER BY items.itemnumber SEPARATOR '|') l_item_type,
192
            GROUP_CONCAT(DISTINCT items.location 
193
                    ORDER BY items.itemnumber SEPARATOR '|') l_location,
194
            GROUP_CONCAT(DISTINCT items.itemcallnumber 
195
                    ORDER BY items.itemnumber SEPARATOR '|') l_itemcallnumber,
196
            GROUP_CONCAT(DISTINCT items.enumchron
197
                    ORDER BY items.itemnumber SEPARATOR '|') l_enumchron,
198
            GROUP_CONCAT(DISTINCT items.copynumber
199
                    ORDER BY items.itemnumber SEPARATOR '|') l_copynumber,
200
            biblio.title,
201
            biblio.subtitle,
202
            biblio.medium,
203
            biblio.part_number,
204
            biblio.part_name,
205
            biblio.author,
206
            count(DISTINCT items.itemnumber) as icount,
207
            count(DISTINCT reserves.borrowernumber) as rcount,
208
            borrowers.firstname,
209
            borrowers.surname
210
    FROM  reserves
211
        LEFT JOIN items ON items.biblionumber=reserves.biblionumber 
212
        LEFT JOIN biblio ON reserves.biblionumber=biblio.biblionumber
213
        LEFT JOIN biblioitems ON biblio.biblionumber=biblioitems.biblionumber
214
        LEFT JOIN branchtransfers ON items.itemnumber=branchtransfers.itemnumber
215
        LEFT JOIN issues ON items.itemnumber=issues.itemnumber
216
        LEFT JOIN borrowers ON reserves.borrowernumber=borrowers.borrowernumber
217
        LEFT JOIN circulation_rules ON ( items.itype=circulation_rules.itemtype AND rule_name = 'holdallowed' AND circulation_rules.branchcode IS NULL AND circulation_rules.categorycode IS NULL )
218
    WHERE
219
    reserves.found IS NULL
220
    $sqldatewhere
221
    AND (reserves.itemnumber IS NULL OR reserves.itemnumber = items.itemnumber)
222
    AND items.itemnumber NOT IN (SELECT itemnumber FROM branchtransfers where datearrived IS NULL)
223
    AND items.itemnumber NOT IN (select itemnumber FROM reserves where found IS NOT NULL)
224
    AND issues.itemnumber IS NULL
225
    AND reserves.priority <> 0 
226
    AND reserves.suspend = 0
227
    AND notforloan = 0 AND itemlost = 0 AND withdrawn = 0
228
    AND ( circulation_rules.rule_value IS NULL OR circulation_rules.rule_value != 0 )
229
    ";
230
    # GROUP BY reserves.biblionumber allows only items that are not checked out, else multiples occur when 
231
    #    multiple patrons have a hold on an item
232
233
234
if (C4::Context->preference('IndependentBranches')){
235
    $strsth .= " AND items.holdingbranch=? ";
236
    push @query_params, C4::Context->userenv->{'branch'};
237
}
180
}
238
$strsth .= " GROUP BY reserves.biblionumber ORDER BY biblio.title ";
181
239
182
# get all distinct unfulfilled reserves
240
my $sth = $dbh->prepare($strsth);
183
my @distinct_holds = Koha::Holds->search(
241
$sth->execute(@query_params);
184
    { %where },
242
185
    { join => 'itembib', group_by => 'reserve.biblionumber', alias => 'reserve' }
243
while ( my $data = $sth->fetchrow_hashref ) {
186
);
244
    push(
187
245
        @reservedata, {
188
# make final reserves hash and fill with info
246
            reservedate     => $data->{l_reservedate},
189
my $reserves;
247
            firstname       => $data->{firstname} || '',
190
foreach my $dh ( @distinct_holds ){
248
            surname         => $data->{surname},
191
249
            title           => $data->{title},
192
    my $bibnum = $dh->biblionumber;
250
            subtitle        => $data->{subtitle},
193
251
            medium          => $data->{medium},
194
    # get available item types for each biblio
252
            part_number     => $data->{part_number},
195
    my $res_itemtypes;
253
            part_name       => $data->{part_name},
196
    if ( C4::Context->preference('item-level_itypes') ){
254
            author          => $data->{author},
197
        $res_itemtypes = Koha::Items->search(
255
            borrowernumber  => $data->{borrowernumber},
198
            { biblionumber => $bibnum, itype => { '!=', undef }  },
256
            biblionumber    => $data->{biblionumber},
199
            { group_by => 'itype' }
257
            holdingbranches => [split('\|', $data->{l_holdingbranch})],
200
        );
258
            branch          => $data->{l_branch},
201
    } else {
259
            itemcallnumber  => [split('\|', $data->{l_itemcallnumber})],
202
        $res_itemtypes = Koha::Biblioitems->search(
260
            enumchron       => [split('\|', $data->{l_enumchron})],
203
            { biblionumber => $bibnum, itemtype => { '!=', undef }  },
261
            copyno          => [split('\|', $data->{l_copynumber})],
204
            { group_by => 'itemtype' }
262
            count           => $data->{icount},
205
        );
263
            rcount          => $data->{rcount},
206
    }
264
            pullcount       => $data->{icount} <= $data->{rcount} ? $data->{icount} : $data->{rcount},
207
    $reserves->{$bibnum}->{itemtypes} = $res_itemtypes;
265
            itemTypes       => [split('\|', $data->{l_item_type})],
208
266
            locations       => [split('\|', $data->{l_location})],
209
    # get available locations for each biblio
267
            reserve_id      => $data->{reserve_id},
210
    my $res_locations = Koha::Items->search(
268
            holdingbranch   => $data->{holdingbranch},
211
        { biblionumber => $bibnum, location => { '!=', undef }  },
269
            homebranch      => $data->{homebranch},
212
        { group_by => 'location' }
270
            itemnumber      => $data->{itemnumber},
213
    );
271
        }
214
    $reserves->{$bibnum}->{locations} = $res_locations;
215
216
    # get available callnumbers for each biblio
217
    my $res_callnumbers = Koha::Items->search(
218
        { biblionumber => $bibnum, itemcallnumber => { '!=', undef } },
219
        { group_by => 'itemcallnumber' }
220
    );
221
    $reserves->{$bibnum}->{callnumbers} = $res_callnumbers;
222
223
    # get available enumchrons for each biblio
224
    my $res_enumchrons = Koha::Items->search(
225
        { biblionumber => $bibnum, enumchron => { '!=', undef }  },
226
        { group_by => 'enumchron' }
227
    );
228
    $reserves->{$bibnum}->{enumchrons} = $res_enumchrons;
229
230
    # get available copynumbers for each biblio
231
    my $res_copynumbers = Koha::Items->search(
232
        { biblionumber => $bibnum, copynumber => { '!=', undef }  },
233
        { group_by => 'copynumber' }
272
    );
234
    );
235
    $reserves->{$bibnum}->{copynumbers} = $res_copynumbers;
236
237
    # get available holding branches for each biblio
238
    my $res_holdingbranches = Koha::Items->search(
239
        { biblionumber => $bibnum, holdingbranch => { '!=', undef }  },
240
        { group_by => 'holdingbranch' }
241
    );
242
    $reserves->{$bibnum}->{holdingbranches} = $res_holdingbranches;
243
244
    # items available
245
    my $items_count = Koha::Items->search(
246
        { biblionumber => $bibnum },
247
        { select => [ { distinct => 'itemnumber' } ] }
248
    )->count;
249
    $reserves->{$bibnum}->{items_count} = $items_count;
250
251
    # patrons with holds
252
    my $patrons_count = Koha::Holds->search(
253
        { biblionumber => $bibnum },
254
        { select => [ { distinct => 'borrowernumber' } ] }
255
    )->count;
256
    $reserves->{$bibnum}->{patrons_count} = $patrons_count;
257
258
    my $pull_count = $items_count <= $patrons_count ? $items_count : $patrons_count;
259
    $reserves->{$bibnum}->{pull_count} = $pull_count;
260
261
    # get other relevant information
262
    my $res_info = Koha::Holds->search(
263
        { 'reserve.biblionumber' => $bibnum, %where },
264
        { prefetch => [ 'borrowernumber', 'itembib', 'biblio' ],
265
          order_by => 'reserve.reservedate',
266
          alias => 'reserve'
267
        }
268
    )->next; # get first item in results
269
    $reserves->{$bibnum}->{borrower} = $res_info->borrower;
270
    $reserves->{$bibnum}->{item} = $res_info->item;
271
    $reserves->{$bibnum}->{biblio} = $res_info->biblio;
272
    $reserves->{$bibnum}->{reserve} = $res_info;
273
}
273
}
274
$sth->finish;
275
274
276
$template->param(
275
$template->param(
277
    todaysdate          => $today,
276
    todaysdate          => $today,
278
    from                => $startdate,
277
    from                => $startdate,
279
    to                  => $enddate,
278
    to                  => $enddate,
280
    reserveloop         => \@reservedata,
279
    reserves            => $reserves,
281
    "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
280
    "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
282
    HoldsToPullStartDate => C4::Context->preference('HoldsToPullStartDate') || PULL_INTERVAL,
281
    HoldsToPullStartDate => C4::Context->preference('HoldsToPullStartDate') || PULL_INTERVAL,
283
    HoldsToPullEndDate  => C4::Context->preference('ConfirmFutureHolds') || 0,
282
    HoldsToPullEndDate  => C4::Context->preference('ConfirmFutureHolds') || 0,
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt (-40 / +38 lines)
Lines 47-53 Link Here
47
<h3>Reported on [% todaysdate | $KohaDates %]</h3>
47
<h3>Reported on [% todaysdate | $KohaDates %]</h3>
48
<p>The following holds have not been filled. Please retrieve them and check them in.</p>
48
<p>The following holds have not been filled. Please retrieve them and check them in.</p>
49
<div id="searchresults">
49
<div id="searchresults">
50
    [% IF ( reserveloop ) %]
50
    [% IF ( reserves ) %]
51
    <table id="holdst">
51
    <table id="holdst">
52
    <thead>
52
    <thead>
53
        <tr>
53
        <tr>
Lines 67-85 Link Here
67
        </tr>
67
        </tr>
68
    </thead>
68
    </thead>
69
    <tbody>
69
    <tbody>
70
        [% FOREACH reserveloo IN reserveloop %]
70
        [% FOREACH reserve IN reserves %]
71
        <tr>
71
        <tr>
72
        [% IF ( reserveloo.borrowernumber ) %]
72
        [% IF ( reserve.value.borrower ) %]
73
            <td><p><b>[% reserveloo.pullcount | html %]</b></p></td>
73
            <td><p><b>[% reserve.value.pull_count | html %]</b></p></td>
74
            <td>[% reserveloo.count | html %]</td>
74
            <td>[% reserve.value.items_count | html %]</td>
75
            <td>[% reserveloo.rcount | html %]</td>
75
            <td>[% reserve.value.patrons_count | html %]</td>
76
            <td><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% reserveloo.borrowernumber | uri %]">[% reserveloo.firstname | html %] [% reserveloo.surname | html %]</a></td>
76
            <td><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% reserve.value.borrower.borrowernumber | uri %]">[% reserve.value.borrower.firstname | html %] [% reserve.value.borrower.surname | html %]</a></td>
77
            <td>
77
            <td>
78
            <p>
78
            <p>
79
                [% INCLUDE 'biblio-default-view.inc' biblionumber = reserveloo.biblionumber %]
79
                [% INCLUDE 'biblio-default-view.inc' biblionumber = reserve.value.biblio.biblionumber %]
80
                    [% INCLUDE 'biblio-title.inc' biblio=reserveloo %]
80
                    [% INCLUDE 'biblio-title.inc' biblio=reserve.value.biblio %]
81
                </a></p>
81
                </a></p>
82
                [% IF ( reserveloo.author ) %]<p> by [% reserveloo.author | html %]</p>[% END %]
82
                [% IF ( reserve.value.biblio.author ) %]<p> by [% reserve.value.biblio.author | html %]</p>[% END %]
83
            </td>
83
            </td>
84
        [% ELSE %]
84
        [% ELSE %]
85
            <td>"</td>
85
            <td>"</td>
Lines 89-165 Link Here
89
            <td>"</td>
89
            <td>"</td>
90
        [% END %]
90
        [% END %]
91
        <td>
91
        <td>
92
            [% IF ( reserveloo.holdingbranches ) %]
92
            [% IF ( reserve.value.holdingbranches ) %]
93
               <ul>
93
                [% FOREACH holdingbranch IN reserve.value.holdingbranches %]
94
                    [% FOREACH holdingbranch IN reserveloo.holdingbranches %]
94
                    [% Branches.GetName ( holdingbranch.holdingbranch ) | html %]
95
                        <li>
95
                [% END %]
96
                            [% Branches.GetName ( holdingbranch ) | html %]
97
                        </li>
98
                    [% END %]
99
               </ul>
100
            [% END %]
96
            [% END %]
101
        </td>
97
        </td>
102
        <td>
98
        <td>
103
            [% IF ( reserveloo.itemcallnumber ) %]
99
            [% IF ( reserve.value.callnumbers ) %]
104
                <ul>
100
                <ul>
105
                    [% FOREACH itemcallnumber IN reserveloo.itemcallnumber  %]
101
                    [% FOREACH callnumber IN reserve.value.callnumbers %]
106
                        <li>
102
                        <li>
107
                            [% itemcallnumber | html %]
103
                            [% callnumber.itemcallnumber | html %]
108
                        </li>
104
                        </li>
109
                    [% END %]
105
                    [% END %]
110
                </ul>
106
                </ul>
111
            [% END %]
107
            [% END %]
112
        </td>
108
        </td>
113
        <td>
109
        <td>
114
            [% IF ( reserveloo.copyno ) %]
110
            [% IF ( reserve.value.copynumbers ) %]
115
                <ul>
111
                <ul>
116
                    [% FOREACH copyno IN reserveloo.copyno %]
112
                    [% FOREACH copyno IN reserve.value.copynumbers %]
117
                        <li>
113
                        <li>
118
                            [% copyno | html %]
114
                            [% copyno.copynumber | html %]
119
                        </li>
115
                        </li>
120
                    [% END %]
116
                    [% END %]
121
                </ul>
117
                </ul>
122
            [% END %]
118
            [% END %]
123
        </td>
119
        </td>
124
        <td>
120
        <td>
125
            [% IF ( reserveloo.enumchron ) %]
121
            [% IF ( reserve.value.enumchrons ) %]
126
                <ul>
122
                <ul>
127
                    [% FOREACH enumchron IN reserveloo.enumchron %]
123
                    [% FOREACH enumchron IN reserve.value.enumchrons %]
128
                        <li>
124
                        <li>
129
                            [% enumchron | html %]
125
                            [% enumchron.enumchron | html %]
130
                        </li>
126
                        </li>
131
                    [% END %]
127
                    [% END %]
132
                </ul>
128
                </ul>
133
            [% END %]
129
            [% END %]
134
        </td>
130
        </td>
135
        <td>
131
        <td>
136
        [% FOREACH itemType IN reserveloo.itemTypes %]
132
        [% FOREACH type IN reserve.value.itemtypes %]
137
            [% ItemTypes.GetDescription( itemType ) | html %]
133
            [% IF Koha.Preference('item-level_itypes') %]
134
                [% ItemTypes.GetDescription( type.itype ) | html %]
135
            [% ELSE %]
136
                [% ItemTypes.GetDescription( type.itemtype ) | html %]
137
            [% END %]
138
        [% END %]
138
        [% END %]
139
        </td>
139
        </td>
140
        <td>
140
        <td>
141
        [% FOREACH loc IN reserveloo.locations %]
141
        [% FOREACH loc IN reserve.value.locations %]
142
            [% AuthorisedValues.GetByCode('LOC', loc) | html %]
142
            [% AuthorisedValues.GetByCode('LOC', loc.location) | html %]
143
        [% END %]
143
        [% END %]
144
        </td>
144
        </td>
145
        <td>
145
        <td>
146
            <span title="[% reserveloo.reservedate | html %]">[% reserveloo.reservedate | $KohaDates %] in [% Branches.GetName ( reserveloo.branch ) | html %]</span>
146
            <span title="[% reserve.value.reserve.reservedate | html %]">[% reserve.value.reserve.reservedate | $KohaDates %] in [% Branches.GetName ( reserve.value.reserve.branchcode ) | html %]</span>
147
        </td>
147
        </td>
148
        <td>
148
        <td>
149
            <form name="cancelReserve" action="/cgi-bin/koha/circ/pendingreserves.pl" method="post">
149
            <form name="cancelReserve" action="/cgi-bin/koha/circ/pendingreserves.pl" method="post">
150
                <input type="hidden" name="op" value="cancel_reserve" />
150
                <input type="hidden" name="op" value="cancel_reserve" />
151
                <input type="hidden" name="reserve_id" value="[% reserveloo.reserve_id | html %]" />
151
                <input type="hidden" name="reserve_id" value="[% reserve.value.reserve.reserve_id | html %]" />
152
                [% IF reserveloo.holdingbranch != reserveloo.homebranch %]
152
                [% IF reserve.value.item.holdingbranch != reserve.value.item.homebranch %]
153
                    <input type="submit" value="Cancel hold and return to : [% Branches.GetName( reserveloo.homebranch ) | html %]" />
153
                    <input type="submit" value="Cancel hold and return to : [% Branches.GetName( reserve.value.itemhomebranch ) | html %]" />
154
                [% ELSE %]
154
                [% ELSE %]
155
                    <input type="submit" value="Cancel hold" />
155
                    <input type="submit" value="Cancel hold" />
156
                [% END %]
156
                [% END %]
157
            </form>
157
            </form>
158
158
159
        [% IF Koha.Preference('CanMarkHoldsToPullAsLost') != 'do_not_allow' %]
159
        [% IF Koha.Preference('CanMarkHoldsToPullAsLost') != 'do_not_allow' %]
160
            [% IF reserveloo.itemnumber %]
160
            [% IF reserve.value.reserve.itemnumber %]
161
                <form name="cancelReserve" action="/cgi-bin/koha/circ/pendingreserves.pl" method="post">
161
                <form name="cancelReserve" action="/cgi-bin/koha/circ/pendingreserves.pl" method="post">
162
                    <input type="hidden" name="reserve_id" value="[% reserveloo.reserve_id | html %]" />
162
                    <input type="hidden" name="reserve_id" value="[% reserve.value.reserve.reserve_id | html %]" />
163
                    [% IF Koha.Preference('CanMarkHoldsToPullAsLost') == 'allow' %]
163
                    [% IF Koha.Preference('CanMarkHoldsToPullAsLost') == 'allow' %]
164
                        <input type="hidden" name="op" value="mark_as_lost" />
164
                        <input type="hidden" name="op" value="mark_as_lost" />
165
                        <input type="submit" value="Mark item as lost" />
165
                        <input type="submit" value="Mark item as lost" />
Lines 284-291 Link Here
284
          $("#homebranchfilter").each( function () {
284
          $("#homebranchfilter").each( function () {
285
              $(this).html( createSelect( holdst.fnGetColumnData(5) ) );
285
              $(this).html( createSelect( holdst.fnGetColumnData(5) ) );
286
              $('select', this).change( function () {
286
              $('select', this).change( function () {
287
                  var filter_value = $(this).val();
287
                  holdst.fnFilter( $(this).child().val(), 5 );
288
                  holdst.fnFilter( filter_value, 5, true );
289
              });
288
              });
290
          });
289
          });
291
          $("#itemtype-filter").each( function () {
290
          $("#itemtype-filter").each( function () {
292
- 

Return to bug 24488