Bug 33653: Never consider received orders as late
[koha.git] / Koha / Acquisition / Orders.pm
1 package Koha::Acquisition::Orders;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20
21 use Koha::Database;
22
23 use Koha::DateUtils qw( dt_from_string );
24 use Koha::Acquisition::Order;
25 use Koha::Exception;
26
27 use base qw(Koha::Objects);
28
29 =head1 NAME
30
31 Koha::Acquisition::Orders object set class
32
33 =head1 API
34
35 =head2 Class methods
36
37 =head3 filter_by_lates
38
39 my $late_orders = $orders->filter_by_lates($params);
40
41 Filter an order set given different parameters.
42
43 This is the equivalent method of the former GetLateOrders C4 subroutine
44
45 $params can be:
46
47 =over
48
49 =item C<delay> the number of days the basket has been closed
50
51 =item C<bookseller_id> the bookseller id
52
53 =item C<estimated_from> Beginning of the estimated delivery date
54
55 =item C<estimated_to> End of the estimated delivery date
56
57 =back
58
59 =cut
60
61 sub filter_by_lates {
62     my ( $self, $params ) = @_;
63     my $delay = $params->{delay};
64     my $bookseller_id = $params->{bookseller_id};
65     # my $branchcode = $params->{branchcode}; # FIXME do we really need this
66     my $estimated_from = $params->{estimated_from};
67     my $estimated_to = $params->{estimated_to};
68     my $dtf = Koha::Database->new->schema->storage->datetime_parser;
69
70     my @delivery_time_conditions;
71     my $date_add = "DATE_ADD(basketno.closedate, INTERVAL COALESCE(booksellerid.deliverytime, booksellerid.deliverytime, 0) day)";
72     my @estimated_delivery_time_conditions;
73     if ( defined $estimated_from or defined $estimated_to ) {
74         push @delivery_time_conditions, \[ "$date_add IS NOT NULL" ];
75         push @delivery_time_conditions, \[ "estimated_delivery_date IS NULL" ];
76         push @estimated_delivery_time_conditions, \[ "estimated_delivery_date IS NOT NULL" ];
77     }
78     if ( defined $estimated_from ) {
79         push @delivery_time_conditions, \[ "$date_add >= ?", $dtf->format_date($estimated_from) ];
80         push @estimated_delivery_time_conditions, \[ "estimated_delivery_date >= ?", $dtf->format_date($estimated_from) ];
81     }
82     if ( defined $estimated_to ) {
83         push @delivery_time_conditions, \[ "$date_add <= ?", $dtf->format_date($estimated_to) ];
84         push @estimated_delivery_time_conditions, \[ "estimated_delivery_date <= ?", $dtf->format_date($estimated_to) ];
85     }
86     if ( defined $estimated_from and not defined $estimated_to ) {
87         push @delivery_time_conditions, \[ "$date_add <= ?", $dtf->format_date(dt_from_string) ];
88         push @estimated_delivery_time_conditions, \[ "estimated_delivery_date <= ?", $dtf->format_date(dt_from_string) ];
89     }
90
91     $self->search(
92         {
93             -or => [
94                 { datereceived => undef },
95                 quantityreceived => { '<' => \'quantity' }
96             ],
97             'basketno.closedate' => [
98                 -and =>
99                 { '!=' => undef },
100                 {
101                     defined $delay
102                     ? (
103                         '<=' => $dtf->format_date(
104                             dt_from_string->subtract( days => $delay )
105                         )
106                       )
107                     : ()
108                 }
109               ],
110             'datecancellationprinted' => undef,
111             (
112                 $bookseller_id
113                 ? ( 'basketno.booksellerid' => $bookseller_id )
114                 : ()
115             ),
116
117             # ( $branchcode ? ('borrower.branchcode')) # FIXME branch is not a filter we may not need to implement this
118
119             ( ( @delivery_time_conditions and @estimated_delivery_time_conditions ) ?
120                 ( -or =>
121                     [
122                         -and => \@estimated_delivery_time_conditions,
123                         -and => \@delivery_time_conditions
124                     ]
125                 )
126                 : ()
127             ),
128             (
129                 C4::Context->preference('IndependentBranches')
130                   && !C4::Context->IsSuperLibrarian
131                 ? ( 'borrower.branchcode' => C4::Context->userenv->{branch} )
132                 : ()
133             ),
134
135             ( orderstatus => { '-not_in' => ['cancelled', 'complete'] } ),
136
137         },
138         {
139             '+select' => [
140                 \"DATE_ADD(basketno.closedate, INTERVAL COALESCE(booksellerid.deliverytime, booksellerid.deliverytime, 0) day)",
141             ],
142             '+as' => [qw/
143                 calculated_estimated_delivery_date
144             /],
145             join => { 'basketno' => 'booksellerid' },
146             prefetch => {'basketno' => 'booksellerid'},
147         }
148     );
149 }
150
151 =head3 filter_by_active
152
153     my $new_rs = $orders->filter_by_active;
154
155 Returns a new resultset filtering orders that are not active.
156
157 =cut
158
159 sub filter_by_active {
160     my ($self) = @_;
161     return $self->search(
162         {
163             '-or' => [
164                 { 'basket.is_standing' => 1,
165                   'orderstatus' => [ 'new', 'ordered', 'partial' ] },
166                 { 'orderstatus' => [ 'ordered', 'partial' ] }
167             ]
168         },
169         { join => 'basket' }
170     );
171 }
172
173 =head3 filter_by_current
174
175     $orders->filter_by_current
176
177 Return the orders of the set that have not been cancelled.
178
179 =cut
180
181 sub filter_by_current {
182     my ($self) = @_;
183     return $self->search(
184         {
185             datecancellationprinted => undef,
186         }
187     );
188 }
189
190 =head3 filter_by_cancelled
191
192     $orders->filter_by_cancelled
193
194 Return the orders of the set that have been cancelled.
195
196 =cut
197
198 sub filter_by_cancelled {
199     my ($self) = @_;
200     return $self->search(
201         {
202             datecancellationprinted => { '!=' => undef }
203         }
204     );
205 }
206
207 =head3 filter_by_id_including_transfers
208
209     my $orders = $orders->filter_by_id_including_transfers(
210         {
211             ordernumber => $ordernumber
212         }
213     );
214
215 When searching for orders by I<ordernumber>, include the aqorders_transfers table
216 so we can find orders that have changed their ordernumber as the result of a transfer
217
218 =cut
219
220 sub filter_by_id_including_transfers {
221     my ( $self, $params ) = @_;
222
223     Koha::Exceptions::MissingParameter->throw( "The ordernumber param is mandatory" )
224         unless $params->{ordernumber};
225
226     return $self->search(
227         {
228             -or => [
229                 { 'me.ordernumber' => $params->{ordernumber} },
230                 { 'aqorders_transfers_ordernumber_to.ordernumber_from' => $params->{ordernumber} }
231             ]
232         },
233         { join => 'aqorders_transfers_ordernumber_to' }
234     );
235 }
236
237 =head2 Internal methods
238
239 =head3 _type
240
241 =cut
242
243 sub _type {
244     return 'Aqorder';
245 }
246
247 =head3 object_class
248
249 =cut
250
251 sub object_class {
252     return 'Koha::Acquisition::Order';
253 }
254
255 1;