Bug 30518: Correct DateTime maths for needs_advancing
[koha.git] / Koha / Acquisition / Basket.pm
1 package Koha::Acquisition::Basket;
2
3 # Copyright 2017 Aleisha Amohia <aleisha@catalyst.net.nz>
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use Koha::Database;
23 use Koha::DateUtils qw( dt_from_string );
24 use Koha::Acquisition::BasketGroups;
25 use Koha::Acquisition::Orders;
26 use Koha::Exceptions::Acquisition::Basket;
27 use Koha::Patrons;
28 use C4::Log qw( logaction );
29
30 use base qw( Koha::Object Koha::Object::Mixin::AdditionalFields );
31
32 =head1 NAME
33
34 Koha::Acquisition::Basket - Koha Basket Object class
35
36 =head1 API
37
38 =head2 Class methods
39
40 =cut
41
42 =head3 bookseller
43
44 Returns the vendor
45
46 =cut
47
48 sub bookseller {
49     my ($self) = @_;
50     my $bookseller_rs = $self->_result->booksellerid;
51     return Koha::Acquisition::Bookseller->_new_from_dbic( $bookseller_rs );
52 }
53
54 =head3 creator
55
56     my $creator = $basket->creator;
57
58 Returns the I<Koha::Patron> for the basket creator.
59
60 =cut
61
62 sub creator {
63     my ($self) = @_;
64     my $borrowernumber = $self->authorisedby; # FIXME missing FK here
65     return unless $borrowernumber;
66     return Koha::Patrons->find( $borrowernumber );
67 }
68
69 =head3 basket_group
70
71 Returns the basket group associated to this basket
72
73 =cut
74
75 sub basket_group {
76     my ($self) = @_;
77
78     my $basket_group_rs = $self->_result->basket_group;
79     return unless $basket_group_rs;
80     return Koha::Acquisition::BasketGroup->_new_from_dbic( $basket_group_rs );
81 }
82
83 =head3 orders
84
85     my $orders = $basket->orders;
86
87 Returns a Koha::Acquisition::Orders resultset, with the orders linked
88 to this basket.
89
90 =cut
91
92 sub orders {
93     my ($self) = @_;
94
95     my $orders_rs = $self->_result->orders;
96     return Koha::Acquisition::Orders->_new_from_dbic( $orders_rs );
97 }
98
99 =head3 edi_order
100
101   my $edi_order = $basket->edi_order;
102
103 Returns the most recently attached EDI order object if one exists for the basket.
104
105 NOTE: This currently returns a bare DBIx::Class result or undefined. This is consistent with the rest of EDI;
106 However it would be beneficial to convert these to full fledge Koha::Objects in the future.
107
108 =cut
109
110 sub edi_order {
111     my ($self) = @_;
112
113     my $order_rs = $self->_result->edifact_messages(
114         {
115             message_type => 'ORDERS',
116             deleted      => 0
117         },
118         { order_by => { '-desc' => 'transfer_date' }, rows => 1 }
119     );
120     return $order_rs->single;
121 }
122
123 =head3 effective_create_items
124
125 Returns C<create_items> for this basket, falling back to C<AcqCreateItem> if unset.
126
127 =cut
128
129 sub effective_create_items {
130     my ( $self ) = @_;
131
132     return $self->create_items || C4::Context->preference('AcqCreateItem');
133 }
134
135 =head3 estimated_delivery_date
136
137 my $estimated_delivery_date = $basket->estimated_delivery_date;
138
139 Return the estimated delivery date for this basket.
140
141 It is calculated adding the delivery time of the vendor to the close date of this basket.
142
143 Return implicit undef if the basket is not closed, or the vendor does not have a delivery time.
144
145 =cut
146
147 sub estimated_delivery_date {
148     my ( $self ) = @_;
149     return unless $self->closedate and $self->bookseller->deliverytime;
150     return dt_from_string($self->closedate)->add( days => $self->bookseller->deliverytime);
151 }
152
153 =head3 late_since_days
154
155 my $number_of_days_late = $basket->late_since_days;
156
157 Return the number of days the basket is late.
158
159 Return implicit undef if the basket is not closed.
160
161 =cut
162
163 sub late_since_days {
164     my ( $self ) = @_;
165     return unless $self->closedate;
166     return dt_from_string->delta_days(dt_from_string($self->closedate))->delta_days();
167 }
168
169 =head3 authorizer
170
171 my $authorizer = $basket->authorizer;
172
173 Returns the patron who authorized/created this basket.
174
175 =cut
176
177 sub authorizer {
178     my ($self) = @_;
179     # FIXME We should use a DBIC rs, but the FK is missing
180     return unless $self->authorisedby;
181     return scalar Koha::Patrons->find($self->authorisedby);
182 }
183
184 =head3 is_closed
185
186     if ( $basket->is_closed ) { ... }
187
188 Returns a boolean value representing if the basket is closed.
189
190 =cut
191
192 sub is_closed {
193     my ($self) = @_;
194
195     return ($self->closedate) ? 1 : 0;
196 }
197
198 =head3 close
199
200     $basket->close;
201
202 Close the basket and mark all open orders as ordered.
203
204 A I<Koha::Exceptions::Acquisition::Basket::AlreadyClosed> exception is thrown
205 if the basket is already closed.
206
207 =cut
208
209 sub close {
210     my ($self) = @_;
211
212     Koha::Exceptions::Acquisition::Basket::AlreadyClosed->throw
213         if $self->is_closed;
214
215     $self->_result->result_source->schema->txn_do(
216         sub {
217             my $open_orders = $self->orders->search(
218                 {
219                     orderstatus => { not_in => [ 'complete', 'cancelled' ] }
220                 }
221             );
222             # Mark open orders as ordered
223             $open_orders->update({ orderstatus => 'ordered' }, { no_triggers => 1 });
224             # set as closed
225             $self->set({ closedate => \'NOW()' })->store;
226         }
227     );
228
229     # Log the closure
230     if (C4::Context->preference("AcquisitionLog")) {
231         logaction(
232             'ACQUISITIONS',
233             'CLOSE_BASKET',
234             $self->id
235         );
236     }
237
238     return $self;
239 }
240
241 =head3 to_api
242
243     my $json = $basket->to_api;
244
245 Overloaded method that returns a JSON representation of the Koha::Acquisition::Basket object,
246 suitable for API output.
247
248 =cut
249
250 sub to_api {
251     my ( $self, $params ) = @_;
252
253     my $json = $self->SUPER::to_api( $params );
254
255     $json->{closed} = ( $self->closedate )
256                                     ? Mojo::JSON->true
257                                     : Mojo::JSON->false;
258
259     return $json;
260 }
261
262 =head3 to_api_mapping
263
264 This method returns the mapping for representing a Koha::Acquisition::Basket object
265 on the API.
266
267 =cut
268
269 sub to_api_mapping {
270     return {
271         basketno                => 'basket_id',
272         basketname              => 'name',
273         booksellernote          => 'vendor_note',
274         contractnumber          => 'contract_id',
275         creationdate            => 'creation_date',
276         closedate               => 'close_date',
277         booksellerid            => 'vendor_id',
278         authorisedby            => 'creator_id',
279         booksellerinvoicenumber => undef,
280         basketgroupid           => 'basket_group_id',
281         deliveryplace           => 'delivery_library_id',
282         billingplace            => 'billing_library_id',
283         branch                  => 'library_id',
284         is_standing             => 'standing'
285     };
286 }
287
288 =head2 Internal methods
289
290 =head3 _type
291
292 =cut
293
294 sub _type {
295     return 'Aqbasket';
296 }
297
298 =head1 AUTHOR
299
300 Aleisha Amohia <aleisha@catalyst.net.nz>
301 Catalyst IT
302
303 =cut
304
305 1;