Bug 24161: Keep tracks of late orders claims
[koha.git] / Koha / Acquisition / Order.pm
blob2747a78fc5c2184c58ae65854972ff9546018bc8
1 package Koha::Acquisition::Order;
3 # This file is part of Koha.
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.
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.
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>.
18 use Modern::Perl;
20 use Carp qw( croak );
22 use Koha::Acquisition::Baskets;
23 use Koha::Acquisition::Funds;
24 use Koha::Acquisition::Invoices;
25 use Koha::Acquisition::Order::Claims;
26 use Koha::Database;
27 use Koha::DateUtils qw( dt_from_string output_pref );
28 use Koha::Biblios;
29 use Koha::Holds;
30 use Koha::Items;
31 use Koha::Subscriptions;
33 use base qw(Koha::Object);
35 =head1 NAME
37 Koha::Acquisition::Order Object class
39 =head1 API
41 =head2 Class methods
43 =head3 new
45 Overloaded I<new> method for backwards compatibility.
47 =cut
49 sub new {
50 my ( $self, $params ) = @_;
52 my $schema = Koha::Database->new->schema;
53 my @columns = $schema->source('Aqorder')->columns;
55 my $values =
56 { map { exists $params->{$_} ? ( $_ => $params->{$_} ) : () } @columns };
57 return $self->SUPER::new($values);
60 =head3 store
62 Overloaded I<store> method for backwards compatibility.
64 =cut
66 sub store {
67 my ($self) = @_;
69 my $schema = Koha::Database->new->schema;
70 # Override quantity for standing orders
71 $self->quantity(1) if ( $self->basketno && $schema->resultset('Aqbasket')->find( $self->basketno )->is_standing );
73 # if these parameters are missing, we can't continue
74 for my $key (qw( basketno quantity biblionumber budget_id )) {
75 croak "Cannot insert order: Mandatory parameter $key is missing"
76 unless $self->$key;
79 if (not defined $self->{created_by}) {
80 my $userenv = C4::Context->userenv;
81 if ($userenv) {
82 $self->created_by($userenv->{number});
86 $self->quantityreceived(0) unless $self->quantityreceived;
87 $self->entrydate(dt_from_string) unless $self->entrydate;
89 $self->ordernumber(undef) unless $self->ordernumber;
90 $self = $self->SUPER::store( $self );
92 unless ( $self->parent_ordernumber ) {
93 $self->set( { parent_ordernumber => $self->ordernumber } );
94 $self = $self->SUPER::store( $self );
97 return $self;
100 =head3 add_item
102 $order->add_item( $itemnumber );
104 Link an item to this order.
106 =cut
108 sub add_item {
109 my ( $self, $itemnumber ) = @_;
111 my $schema = Koha::Database->new->schema;
112 my $rs = $schema->resultset('AqordersItem');
113 $rs->create({ ordernumber => $self->ordernumber, itemnumber => $itemnumber });
116 =head3 basket
118 my $basket = $order->basket;
120 Returns the I<Koha::Acquisition::Basket> object for the basket associated
121 to the order.
123 =cut
125 sub basket {
126 my ( $self ) = @_;
127 my $basket_rs = $self->_result->basket;
128 return Koha::Acquisition::Basket->_new_from_dbic( $basket_rs );
131 =head3 fund
133 my $fund = $order->fund;
135 Returns the I<Koha::Acquisition::Fund> object for the fund (aqbudgets)
136 associated to the order.
138 =cut
140 sub fund {
141 my ( $self ) = @_;
142 my $fund_rs = $self->_result->fund;
143 return Koha::Acquisition::Fund->_new_from_dbic( $fund_rs );
146 =head3 invoice
148 my $invoice = $order->invoice;
150 Returns the I<Koha::Acquisition::Invoice> object for the invoice associated
151 to the order.
153 It returns B<undef> if no linked invoice is found.
155 =cut
157 sub invoice {
158 my ( $self ) = @_;
159 my $invoice_rs = $self->_result->invoice;
160 return unless $invoice_rs;
161 return Koha::Acquisition::Invoice->_new_from_dbic( $invoice_rs );
164 =head3 subscription
166 my $subscription = $order->subscription
168 Returns the I<Koha::Subscription> object for the subscription associated
169 to the order.
171 It returns B<undef> if no linked subscription is found.
173 =cut
175 sub subscription {
176 my ( $self ) = @_;
177 my $subscription_rs = $self->_result->subscription;
178 return unless $subscription_rs;
179 return Koha::Subscription->_new_from_dbic( $subscription_rs );
182 =head3 current_item_level_holds
184 my $holds = $order->current_item_level_holds;
186 Returns the current item-level holds associated to the order. It returns a I<Koha::Holds>
187 resultset.
189 =cut
191 sub current_item_level_holds {
192 my ($self) = @_;
194 my $items_rs = $self->_result->aqorders_items;
195 my @item_numbers = $items_rs->get_column('itemnumber')->all;
196 my $biblio = $self->biblio;
198 unless ( $biblio and @item_numbers ) {
199 return Koha::Holds->new->empty;
202 return $biblio->current_holds->search(
204 itemnumber => {
205 -in => \@item_numbers
211 =head3 items
213 my $items = $order->items
215 Returns the items associated to the order.
217 =cut
219 sub items {
220 my ( $self ) = @_;
221 # aqorders_items is not a join table
222 # There is no FK on items (may have been deleted)
223 my $items_rs = $self->_result->aqorders_items;
224 my @itemnumbers = $items_rs->get_column( 'itemnumber' )->all;
225 return Koha::Items->search({ itemnumber => \@itemnumbers });
228 =head3 biblio
230 my $biblio = $order->biblio
232 Returns the bibliographic record associated to the order
234 =cut
236 sub biblio {
237 my ( $self ) = @_;
238 my $biblio_rs= $self->_result->biblio;
239 return unless $biblio_rs;
240 return Koha::Biblio->_new_from_dbic( $biblio_rs );
243 =head3 claims
245 my $claims = $order->claims
247 Return the claims history for this order
249 =cut
251 sub claims {
252 my ( $self ) = @_;
253 my $claims_rs = $self->_result->aqorders_claims;
254 return Koha::Acquisition::Order::Claims->_new_from_dbic( $claims_rs );
257 =head3 claim
259 my $claim = $order->claim
261 Do claim for this order
263 =cut
265 sub claim {
266 my ( $self ) = @_;
267 my $claim_rs = $self->_result->create_related('aqorders_claims', {});
268 return Koha::Acquisition::Order::Claim->_new_from_dbic($claim_rs);
271 =head3 claims_count
273 my $nb_of_claims = $order->claims_count;
275 This is the equivalent of $order->claims->count. Keeping it for retrocompatibilty.
277 =cut
279 sub claims_count {
280 my ( $self ) = @_;
281 return $self->claims->count;
284 =head3 claimed_date
286 my $last_claim_date = $order->claimed_date;
288 This is the equivalent of $order->claims->last->claimed_on. Keeping it for retrocompatibilty.
290 =cut
292 sub claimed_date {
293 my ( $self ) = @_;
294 my $last_claim = $self->claims->last;
295 return unless $last_claim;
296 return $last_claim->claimed_on;
299 =head3 duplicate_to
301 my $duplicated_order = $order->duplicate_to($basket, [$default_values]);
303 Duplicate an existing order and attach it to a basket. $default_values can be specified as a hashref
304 that contain default values for the different order's attributes.
305 Items will be duplicated as well but barcodes will be set to null.
307 =cut
309 sub duplicate_to {
310 my ( $self, $basket, $default_values ) = @_;
311 my $new_order;
312 $default_values //= {};
313 Koha::Database->schema->txn_do(
314 sub {
315 my $order_info = $self->unblessed;
316 undef $order_info->{ordernumber};
317 for my $field (
319 ordernumber
320 received_on
321 datereceived
322 invoiceid
323 datecancellationprinted
324 cancellationreason
325 purchaseordernumber
326 claims_count
327 claimed_date
328 parent_ordernumber
332 undef $order_info->{$field};
334 $order_info->{placed_on} = dt_from_string;
335 $order_info->{entrydate} = dt_from_string;
336 $order_info->{orderstatus} = 'new';
337 $order_info->{quantityreceived} = 0;
338 while ( my ( $field, $value ) = each %$default_values ) {
339 $order_info->{$field} = $value;
342 my $userenv = C4::Context->userenv;
343 $order_info->{created_by} = $userenv->{number};
344 $order_info->{basketno} = $basket->basketno;
346 $new_order = Koha::Acquisition::Order->new($order_info)->store;
348 if ( ! $self->subscriptionid && $self->basket->effective_create_items eq 'ordering') { # Do copy items if not a subscription order AND if items are created on ordering
349 my $items = $self->items;
350 while ( my ($item) = $items->next ) {
351 my $item_info = $item->unblessed;
352 undef $item_info->{itemnumber};
353 undef $item_info->{barcode};
354 my $new_item = Koha::Item->new($item_info)->store;
355 $new_order->add_item( $new_item->itemnumber );
360 return $new_order;
363 =head3 to_api_mapping
365 This method returns the mapping for representing a Koha::Acquisition::Order object
366 on the API.
368 =cut
370 sub to_api_mapping {
371 return {
372 basketno => 'basket_id',
373 biblionumber => 'biblio_id',
374 budget_id => 'fund_id',
375 budgetdate => undef, # unused
376 cancellationreason => 'cancellation_reason',
377 claimed_date => 'last_claim_date',
378 datecancellationprinted => 'cancellation_date',
379 datereceived => 'date_received',
380 discount => 'discount_rate',
381 entrydate => 'entry_date',
382 freight => 'shipping_cost',
383 invoiceid => 'invoice_id',
384 line_item_id => undef, # EDIFACT related
385 listprice => 'list_price',
386 order_internalnote => 'internal_note',
387 order_vendornote => 'vendor_note',
388 ordernumber => 'order_id',
389 orderstatus => 'status',
390 parent_ordernumber => 'parent_order_id',
391 purchaseordernumber => undef, # obsolete
392 quantityreceived => 'quantity_received',
393 replacementprice => 'replacement_price',
394 sort1 => 'statistics_1',
395 sort1_authcat => 'statistics_1_authcat',
396 sort2 => 'statistics_2',
397 sort2_authcat => 'statistics_2_authcat',
398 subscriptionid => 'subscription_id',
399 suppliers_reference_number => undef, # EDIFACT related
400 suppliers_reference_qualifier => undef, # EDIFACT related
401 suppliers_report => undef, # EDIFACT related
402 tax_rate_bak => undef, # unused
403 tax_value_bak => undef, # unused
404 uncertainprice => 'uncertain_price',
405 unitprice => 'unit_price',
406 unitprice_tax_excluded => 'unit_price_tax_excluded',
407 unitprice_tax_included => 'unit_price_tax_included'
411 =head2 Internal methods
413 =head3 _type
415 =cut
417 sub _type {
418 return 'Aqorder';