3 # Copyright 2014,2015 PTFS-Europe Ltd
5 # This file is part of Koha.
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.
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.
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>.
22 use base
qw(Exporter);
25 use English
qw{ -no_match_vars
};
30 use C4
::Acquisition
qw( NewBasket CloseBasket ModOrder);
31 use C4
::Suggestions
qw( ModSuggestion );
32 use C4
::Items
qw(AddItem);
33 use C4
::Biblio
qw( AddBiblio TransformKohaToMarc GetMarcBiblio );
34 use Koha
::Edifact
::Order
;
38 use Koha
::Plugins
::Handler
;
39 use Koha
::Acquisition
::Baskets
;
40 use Koha
::Acquisition
::Booksellers
;
44 qw( process_quote process_invoice process_ordrsp create_edi_order get_edifact_ean );
46 sub create_edi_order
{
47 my $parameters = shift;
48 my $basketno = $parameters->{basketno
};
49 my $ean = $parameters->{ean
};
50 my $branchcode = $parameters->{branchcode
};
51 my $noingest = $parameters->{noingest
};
52 if ( !$basketno || !$ean ) {
53 carp
'create_edi_order called with no basketno or ean';
57 my $schema = Koha
::Database
->new()->schema();
59 my @orderlines = $schema->resultset('Aqorder')->search(
61 basketno
=> $basketno,
67 carp
"No orderlines for basket $basketno";
71 my $vendor = $schema->resultset('VendorEdiAccount')->search(
73 vendor_id
=> $orderlines[0]->basketno->booksellerid->id,
77 my $ean_search_keys = { ean
=> $ean, };
79 $ean_search_keys->{branchcode
} = $branchcode;
82 $schema->resultset('EdifactEan')->search($ean_search_keys)->single;
84 my $dbh = C4
::Context
->dbh;
85 my $arr_ref = $dbh->selectcol_arrayref(
86 'select id from edifact_messages where basketno = ? and message_type = \'QUOTE\'',
89 my $response = @
{$arr_ref} ?
1 : 0;
91 my $edifact_order_params = {
92 orderlines
=> \
@orderlines,
95 is_response
=> $response,
99 if ( $vendor->plugin ) {
100 $edifact = Koha
::Plugins
::Handler
->run(
102 class => $vendor->plugin,
103 method
=> 'edifact_order',
105 params
=> $edifact_order_params,
111 $edifact = Koha
::Edifact
::Order
->new($edifact_order_params);
114 return unless $edifact;
116 my $order_file = $edifact->encode();
120 my $m = unidecode
($order_file); # remove diacritics and non-latin chars
121 if ($noingest) { # allows scripts to produce test files
125 message_type
=> 'ORDERS',
127 vendor_id
=> $vendor->vendor_id,
129 basketno
=> $basketno,
130 filename
=> $edifact->filename(),
131 transfer_date
=> $edifact->msg_date_string(),
132 edi_acct
=> $vendor->id,
135 $schema->resultset('EdifactMessage')->create($order);
143 my $response_message = shift;
144 $response_message->status('processing');
145 $response_message->update;
146 my $schema = Koha
::Database
->new()->schema();
147 my $logger = Log
::Log4perl
->get_logger();
150 Koha
::Edifact
->new( { transmission
=> $response_message->raw_msg, } );
151 my $messages = $edi->message_array();
153 if ( @
{$messages} ) {
154 foreach my $msg ( @
{$messages} ) {
155 my $lines = $msg->lineitems();
156 foreach my $line ( @
{$lines} ) {
157 my $ordernumber = $line->ordernumber();
159 # action cancelled:change_requested:no_action:accepted:not_found:recorded
160 my $action = $line->action_notification();
161 if ( $action eq 'cancelled' ) {
162 my $reason = $line->coded_orderline_text();
165 ordernumber
=> $ordernumber,
166 cancellationreason
=> $reason,
167 orderstatus
=> 'cancelled',
168 datecancellationprinted
=> DateTime
->now()->ymd(),
172 else { # record order as due with possible further info
174 my $report = $line->coded_orderline_text();
175 my $date_avail = $line->availability_date();
178 $report .= " Available: $date_avail";
182 ordernumber
=> $ordernumber,
183 suppliers_report
=> $report,
191 $response_message->status('received');
192 $response_message->update;
196 sub process_invoice
{
197 my $invoice_message = shift;
198 $invoice_message->status('processing');
199 $invoice_message->update;
200 my $schema = Koha
::Database
->new()->schema();
201 my $logger = Log
::Log4perl
->get_logger();
204 my $plugin = $invoice_message->edi_acct()->plugin();
207 $edi_plugin = Koha
::Plugins
::Handler
->run(
212 invoice_message
=> $invoice_message,
213 transmission
=> $invoice_message->raw_msg,
219 my $edi = $edi_plugin ||
220 Koha
::Edifact
->new( { transmission
=> $invoice_message->raw_msg, } );
222 my $messages = $edi->message_array();
224 if ( @
{$messages} ) {
226 # BGM contains an invoice number
227 foreach my $msg ( @
{$messages} ) {
228 my $invoicenumber = $msg->docmsg_number();
229 my $shipmentcharge = $msg->shipment_charge();
230 my $msg_date = $msg->message_date;
231 my $tax_date = $msg->tax_point_date;
232 if ( !defined $tax_date || $tax_date !~ m/^\d{8}/xms ) {
233 $tax_date = $msg_date;
236 my $vendor_ean = $msg->supplier_ean;
237 if ( !defined $vendor_acct || $vendor_ean ne $vendor_acct->san ) {
238 $vendor_acct = $schema->resultset('VendorEdiAccount')->search(
244 if ( !$vendor_acct ) {
246 "Cannot find vendor with ean $vendor_ean for invoice $invoicenumber in $invoice_message->filename";
249 $invoice_message->edi_acct( $vendor_acct->id );
250 $logger->trace("Adding invoice:$invoicenumber");
251 my $new_invoice = $schema->resultset('Aqinvoice')->create(
253 invoicenumber
=> $invoicenumber,
254 booksellerid
=> $invoice_message->vendor_id,
255 shipmentdate
=> $msg_date,
256 billingdate
=> $tax_date,
257 shipmentcost
=> $shipmentcharge,
258 shipmentcost_budgetid
=> $vendor_acct->shipment_budget,
259 message_id
=> $invoice_message->id,
262 my $invoiceid = $new_invoice->invoiceid;
263 $logger->trace("Added as invoiceno :$invoiceid");
264 my $lines = $msg->lineitems();
266 foreach my $line ( @
{$lines} ) {
267 my $ordernumber = $line->ordernumber;
268 $logger->trace( "Receipting order:$ordernumber Qty: ",
271 my $order = $schema->resultset('Aqorder')->find($ordernumber);
273 # ModReceiveOrder does not validate that $ordernumber exists validate here
277 my $s = $schema->resultset('Suggestion')->search(
279 biblionumber
=> $order->biblionumber->biblionumber,
285 suggestionid
=> $s->suggestionid,
286 STATUS
=> 'AVAILABLE',
291 my $price = _get_invoiced_price
($line);
293 if ( $order->quantity > $line->quantity ) {
294 my $ordered = $order->quantity;
297 $order->orderstatus('partial');
298 $order->quantity( $ordered - $line->quantity );
300 my $received_order = $order->copy(
302 ordernumber
=> undef,
303 quantity
=> $line->quantity,
304 quantityreceived
=> $line->quantity,
305 orderstatus
=> 'complete',
307 invoiceid
=> $invoiceid,
308 datereceived
=> $msg_date,
311 transfer_items
( $schema, $line, $order,
313 receipt_items
( $schema, $line,
314 $received_order->ordernumber );
316 else { # simple receipt all copies on order
317 $order->quantityreceived( $line->quantity );
318 $order->datereceived($msg_date);
319 $order->invoiceid($invoiceid);
320 $order->unitprice($price);
321 $order->orderstatus('complete');
323 receipt_items
( $schema, $line, $ordernumber );
328 "No order found for $ordernumber Invoice:$invoicenumber"
338 $invoice_message->status('received');
339 $invoice_message->update; # status and basketno link
343 sub _get_invoiced_price
{
345 my $price = $line->price_net;
346 if ( !defined $price ) { # no net price so generate it from lineitem amount
347 $price = $line->amt_lineitem;
348 if ( $price and $line->quantity > 1 ) {
349 $price /= $line->quantity; # div line cost by qty
356 my ( $schema, $inv_line, $ordernumber ) = @_;
357 my $logger = Log
::Log4perl
->get_logger();
358 my $quantity = $inv_line->quantity;
360 # itemnumber is not a foreign key ??? makes this a bit cumbersome
361 my @item_links = $schema->resultset('AqordersItem')->search(
363 ordernumber
=> $ordernumber,
367 foreach my $ilink (@item_links) {
368 my $item = $schema->resultset('Item')->find( $ilink->itemnumber );
370 my $i = $ilink->itemnumber;
372 "Cannot find aqorder item for $i :Order:$ordernumber");
375 my $b = $item->homebranch->branchcode;
376 if ( !exists $branch_map{$b} ) {
377 $branch_map{$b} = [];
379 push @
{ $branch_map{$b} }, $item;
381 my $gir_occurrence = 0;
382 while ( $gir_occurrence < $quantity ) {
383 my $branch = $inv_line->girfield( 'branch', $gir_occurrence );
384 my $item = shift @
{ $branch_map{$branch} };
386 my $barcode = $inv_line->girfield( 'barcode', $gir_occurrence );
387 if ( $barcode && !$item->barcode ) {
388 my $rs = $schema->resultset('Item')->search(
393 if ( $rs->count > 0 ) {
394 $logger->warn("Barcode $barcode is a duplicate");
398 $logger->trace("Adding barcode $barcode");
399 $item->barcode($barcode);
406 $logger->warn("Unmatched item at branch:$branch");
415 my ( $schema, $inv_line, $order_from, $order_to ) = @_;
417 # Transfer x items from the orig order to a completed partial order
418 my $quantity = $inv_line->quantity;
420 my %mapped_by_branch;
421 while ( $gocc < $quantity ) {
422 my $branch = $inv_line->girfield( 'branch', $gocc );
423 if ( !exists $mapped_by_branch{$branch} ) {
424 $mapped_by_branch{$branch} = 1;
427 $mapped_by_branch{$branch}++;
431 my $logger = Log
::Log4perl
->get_logger();
432 my $o1 = $order_from->ordernumber;
433 my $o2 = $order_to->ordernumber;
434 $logger->warn("transferring $quantity copies from order $o1 to order $o2");
436 my @item_links = $schema->resultset('AqordersItem')->search(
438 ordernumber
=> $order_from->ordernumber,
441 foreach my $ilink (@item_links) {
442 my $ino = $ilink->itemnumber;
443 my $item = $schema->resultset('Item')->find( $ilink->itemnumber );
444 my $i_branch = $item->homebranch;
445 if ( exists $mapped_by_branch{$i_branch}
446 && $mapped_by_branch{$i_branch} > 0 )
448 $ilink->ordernumber( $order_to->ordernumber );
451 --$mapped_by_branch{$i_branch};
452 $logger->warn("Transferred item $item");
455 $logger->warn("Skipped item $item");
457 if ( $quantity < 1 ) {
468 $quote->status('processing');
471 my $edi = Koha
::Edifact
->new( { transmission
=> $quote->raw_msg, } );
473 my $messages = $edi->message_array();
474 my $process_errors = 0;
475 my $logger = Log
::Log4perl
->get_logger();
476 my $schema = Koha
::Database
->new()->schema();
477 my $message_count = 0;
478 my @added_baskets; # if auto & multiple baskets need to order all
480 if ( @
{$messages} && $quote->vendor_id ) {
481 foreach my $msg ( @
{$messages} ) {
484 NewBasket
( $quote->vendor_id, 0, $quote->filename, q{},
486 push @added_baskets, $basketno;
487 if ( $message_count > 1 ) {
488 my $m_filename = $quote->filename;
489 $m_filename .= "_$message_count";
490 $schema->resultset('EdifactMessage')->create(
492 message_type
=> $quote->message_type,
493 transfer_date
=> $quote->transfer_date,
494 vendor_id
=> $quote->vendor_id,
495 edi_acct
=> $quote->edi_acct,
497 basketno
=> $basketno,
499 filename
=> $m_filename,
504 $quote->basketno($basketno);
506 $logger->trace("Created basket :$basketno");
507 my $items = $msg->lineitems();
508 my $refnum = $msg->message_refno;
510 for my $item ( @
{$items} ) {
511 if ( !quote_item
( $item, $quote, $basketno ) ) {
517 my $status = 'received';
518 if ($process_errors) {
522 $quote->status($status);
523 $quote->update; # status and basketno link
524 # Do we automatically generate orders for this vendor
525 my $v = $schema->resultset('VendorEdiAccount')->search(
527 vendor_id
=> $quote->vendor_id,
530 if ( $v->auto_orders ) {
531 for my $b (@added_baskets) {
546 my ( $item, $quote, $basketno ) = @_;
548 my $schema = Koha
::Database
->new()->schema();
549 my $logger = Log
::Log4perl
->get_logger();
551 my $basket = Koha
::Acquisition
::Baskets
->find( $basketno );
553 $logger->error('Skipping order creation no valid basketno');
556 $logger->trace( 'Checking db for matches with ', $item->item_number_id() );
557 my $bib = _check_for_existing_bib
( $item->item_number_id() );
558 if ( !defined $bib ) {
560 my $bib_record = _create_bib_from_quote
( $item, $quote );
561 ( $bib->{biblionumber
}, $bib->{biblioitemnumber
} ) =
562 AddBiblio
( $bib_record, q{} );
563 $logger->trace("New biblio added $bib->{biblionumber}");
566 $logger->trace("Match found: $bib->{biblionumber}");
569 # Create an orderline
570 my $order_note = $item->{orderline_free_text
};
572 my $order_quantity = $item->quantity();
573 my $gir_count = $item->number_of_girs();
574 $order_quantity ||= 1; # quantity not necessarily present
575 if ( $gir_count > 1 ) {
576 if ( $gir_count != $order_quantity ) {
578 "Order for $order_quantity items, $gir_count segments present");
580 $order_quantity = 1; # attempts to create an orderline for each gir
582 my $vendor = Koha
::Acquisition
::Booksellers
->find( $quote->vendor_id );
584 # database definitions should set some of these defaults but dont
586 biblionumber
=> $bib->{biblionumber
},
587 entrydate
=> DateTime
->now( time_zone
=> 'local' )->ymd(),
588 basketno
=> $basketno,
589 listprice
=> $item->price,
590 quantity
=> $order_quantity,
591 quantityreceived
=> 0,
592 order_vendornote
=> q{},
593 order_internalnote
=> $order_note,
595 ecost
=> _discounted_price
( $quote->vendor->discount, $item->price ),
599 currency
=> $vendor->listprice(),
602 # suppliers references
603 if ( $item->reference() ) {
604 $order_hash->{suppliers_reference_number
} = $item->reference;
605 $order_hash->{suppliers_reference_qualifier
} = 'QLI';
607 elsif ( $item->orderline_reference_number() ) {
608 $order_hash->{suppliers_reference_number
} =
609 $item->orderline_reference_number;
610 $order_hash->{suppliers_reference_qualifier
} = 'SLI';
612 if ( $item->item_number_id ) { # suppliers ean
613 $order_hash->{line_item_id
} = $item->item_number_id;
616 if ( $item->girfield('servicing_instruction') ) {
620 while ( $si = $item->girfield( 'servicing_instruction', $occ ) ) {
627 $order_hash->{order_vendornote
} = $txt;
630 if ( $item->internal_notes() ) {
631 if ( $order_hash->{order_internalnote
} ) { # more than ''
632 $order_hash->{order_internalnote
} .= q{ };
634 $order_hash->{order_internalnote
} .= $item->internal_notes;
637 my $budget = _get_budget
( $schema, $item->girfield('fund_allocation') );
641 if ( $item->quantity > 1 ) {
642 carp
'Skipping line with no budget info';
643 $logger->trace('girfield skipped for invalid budget');
647 carp
'Skipping line with no budget info';
648 $logger->trace('orderline skipped for invalid budget');
658 $order_hash->{budget_id
} = $budget->budget_id;
659 my $first_order = $schema->resultset('Aqorder')->create($order_hash);
660 my $o = $first_order->ordernumber();
661 $logger->trace("Order created :$o");
663 # should be done by database settings
664 $first_order->parent_ordernumber( $first_order->ordernumber() );
665 $first_order->update();
667 # add to $budgets to prevent duplicate orderlines
668 $budgets{ $budget->budget_id } = '1';
670 # record ordernumber against budget
671 $ordernumber{ $budget->budget_id } = $o;
673 if ( C4
::Context
->preference('AcqCreateItem') eq 'ordering' ) {
674 $item_hash = _create_item_from_quote
( $item, $quote );
677 while ( $created < $order_quantity ) {
679 ( $bib->{biblionumber
}, $bib->{biblioitemnumber
}, $itemnumber )
680 = AddItem
( $item_hash, $bib->{biblionumber
} );
681 $logger->trace("Added item:$itemnumber");
682 $schema->resultset('AqordersItem')->create(
684 ordernumber
=> $first_order->ordernumber,
685 itemnumber
=> $itemnumber,
693 if ( $order_quantity == 1 && $item->quantity > 1 ) {
694 my $occurrence = 1; # occ zero already added
695 while ( $occurrence < $item->quantity ) {
698 $budget = _get_budget
( $schema,
699 $item->girfield( 'fund_allocation', $occurrence ) );
703 $item->girfield( 'fund_allocation', $occurrence );
704 carp
'Skipping line with no budget info';
706 "girfield skipped for invalid budget:$bad_budget");
707 ++$occurrence; ## lets look at the next one not this one again
711 # add orderline for NEW budget in $budgets
712 if ( !exists $budgets{ $budget->budget_id } ) {
714 # $order_hash->{quantity} = 1; by default above
715 # we should handle both 1:1 GIR & 1:n GIR (with LQT values) here
717 $order_hash->{budget_id
} = $budget->budget_id;
720 $schema->resultset('Aqorder')->create($order_hash);
721 my $o = $new_order->ordernumber();
722 $logger->trace("Order created :$o");
724 # should be done by database settings
725 $new_order->parent_ordernumber( $new_order->ordernumber() );
726 $new_order->update();
728 # add to $budgets to prevent duplicate orderlines
729 $budgets{ $budget->budget_id } = '1';
731 # record ordernumber against budget
732 $ordernumber{ $budget->budget_id } = $o;
734 if ( C4
::Context
->preference('AcqCreateItem') eq 'ordering' ) {
735 if ( !defined $item_hash ) {
736 $item_hash = _create_item_from_quote
( $item, $quote );
740 $item->girfield( 'stock_category', $occurrence ),
742 $item->girfield( 'collection_code', $occurrence ),
744 $item->girfield( 'shelfmark', $occurrence )
745 || $item->girfield( 'classification', $occurrence )
746 || title_level_class
($item),
748 $item->girfield( 'branch', $occurrence ),
749 homebranch
=> $item->girfield( 'branch', $occurrence ),
751 if ( $new_item->{itype
} ) {
752 $item_hash->{itype
} = $new_item->{itype
};
754 if ( $new_item->{location
} ) {
755 $item_hash->{location
} = $new_item->{location
};
757 if ( $new_item->{itemcallnumber
} ) {
758 $item_hash->{itemcallnumber
} =
759 $new_item->{itemcallnumber
};
761 if ( $new_item->{holdingbranch
} ) {
762 $item_hash->{holdingbranch
} =
763 $new_item->{holdingbranch
};
765 if ( $new_item->{homebranch
} ) {
766 $item_hash->{homebranch
} = $new_item->{homebranch
};
770 ( undef, undef, $itemnumber ) =
771 AddItem
( $item_hash, $bib->{biblionumber
} );
772 $logger->trace("New item $itemnumber added");
773 $schema->resultset('AqordersItem')->create(
775 ordernumber
=> $new_order->ordernumber,
776 itemnumber
=> $itemnumber,
784 # increment quantity in orderline for EXISTING budget in $budgets
786 my $row = $schema->resultset('Aqorder')->find(
788 ordernumber
=> $ordernumber{ $budget->budget_id }
792 my $qty = $row->quantity;
801 if ( $basket->effective_create_item eq 'ordering' ) {
806 price
=> $item->price,
807 replacementprice
=> $item->price,
809 $item->girfield( 'stock_category', $occurrence ),
811 $item->girfield( 'collection_code', $occurrence ),
813 $item->girfield( 'shelfmark', $occurrence )
814 || $item->girfield( 'classification', $occurrence )
815 || $item_hash->{itemcallnumber
},
817 $item->girfield( 'branch', $occurrence ),
818 homebranch
=> $item->girfield( 'branch', $occurrence ),
821 ( undef, undef, $itemnumber ) =
822 AddItem
( $new_item, $bib->{biblionumber
} );
823 $logger->trace("New item $itemnumber added");
824 $schema->resultset('AqordersItem')->create(
826 ordernumber
=> $ordernumber{ $budget->budget_id },
827 itemnumber
=> $itemnumber,
840 sub get_edifact_ean
{
842 my $dbh = C4
::Context
->dbh;
844 my $eans = $dbh->selectcol_arrayref('select ean from edifact_ean');
849 # We should not need to have a routine to do this here
850 sub _discounted_price
{
851 my ( $discount, $price ) = @_;
852 return $price - ( ( $discount * $price ) / 100 );
855 sub _check_for_existing_bib
{
858 my $search_isbn = $isbn;
859 $search_isbn =~ s/^\s*/%/xms;
860 $search_isbn =~ s/\s*$/%/xms;
861 my $dbh = C4
::Context
->dbh;
862 my $sth = $dbh->prepare(
863 'select biblionumber, biblioitemnumber from biblioitems where isbn like ?',
866 $dbh->selectall_arrayref( $sth, { Slice
=> {} }, $search_isbn );
867 if ( @
{$tuple_arr} ) {
868 return $tuple_arr->[0];
870 elsif ( length($isbn) == 13 && $isbn !~ /^97[89]/ ) {
871 my $tarr = $dbh->selectall_arrayref(
872 'select biblionumber, biblioitemnumber from biblioitems where ean = ?',
883 if ( $isbn =~ m/(\d{13})/xms ) {
884 my $b_isbn = Business
::ISBN
->new($1);
885 if ( $b_isbn && $b_isbn->is_valid ) {
886 $search_isbn = $b_isbn->as_isbn10->as_string( [] );
890 elsif ( $isbn =~ m/(\d{9}[xX]|\d{10})/xms ) {
891 my $b_isbn = Business
::ISBN
->new($1);
892 if ( $b_isbn && $b_isbn->is_valid ) {
893 $search_isbn = $b_isbn->as_isbn13->as_string( [] );
898 $search_isbn = "%$search_isbn%";
900 $dbh->selectall_arrayref( $sth, { Slice
=> {} }, $search_isbn );
901 if ( @
{$tuple_arr} ) {
902 return $tuple_arr->[0];
909 # returns a budget obj or undef
910 # fact we need this shows what a mess Acq API is
912 my ( $schema, $budget_code ) = @_;
913 my $period_rs = $schema->resultset('Aqbudgetperiod')->search(
915 budget_period_active
=> 1,
919 # db does not ensure budget code is unque
920 return $schema->resultset('Aqbudget')->single(
922 budget_code
=> $budget_code,
924 { -in => $period_rs->get_column('budget_period_id')->as_query },
929 # try to get title level classification from incoming quote
930 sub title_level_class
{
933 my $default_scheme = C4
::Context
->preference('DefaultClassificationSource');
934 if ( $default_scheme eq 'ddc' ) {
935 $class = $item->dewey_class();
937 elsif ( $default_scheme eq 'lcc' ) {
938 $class = $item->lc_class();
942 $item->girfield('shelfmark')
943 || $item->girfield('classification')
949 sub _create_bib_from_quote
{
951 #TBD we should flag this for updating from an external source
952 #As biblio (&biblioitems) has no candidates flag in order
953 my ( $item, $quote ) = @_;
954 my $itemid = $item->item_number_id;
955 my $defalt_classification_source =
956 C4
::Context
->preference('DefaultClassificationSource');
958 'biblioitems.cn_source' => $defalt_classification_source,
959 'items.cn_source' => $defalt_classification_source,
960 'items.notforloan' => -1,
961 'items.cn_sort' => q{},
963 $bib_hash->{'biblio.seriestitle'} = $item->series;
965 $bib_hash->{'biblioitems.publishercode'} = $item->publisher;
966 $bib_hash->{'biblioitems.publicationyear'} =
967 $bib_hash->{'biblio.copyrightdate'} = $item->publication_date;
969 $bib_hash->{'biblio.title'} = $item->title;
970 $bib_hash->{'biblio.author'} = $item->author;
971 $bib_hash->{'biblioitems.isbn'} = $item->item_number_id;
972 $bib_hash->{'biblioitems.itemtype'} = $item->girfield('stock_category');
974 # If we have a 13 digit id we are assuming its an ean
975 # (it may also be an isbn or issn)
976 if ( $itemid =~ /^\d{13}$/ ) {
977 $bib_hash->{'biblioitems.ean'} = $itemid;
978 if ( $itemid =~ /^977/ ) {
979 $bib_hash->{'biblioitems.issn'} = $itemid;
982 for my $key ( keys %{$bib_hash} ) {
983 if ( !defined $bib_hash->{$key} ) {
984 delete $bib_hash->{$key};
987 return TransformKohaToMarc
($bib_hash);
991 sub _create_item_from_quote
{
992 my ( $item, $quote ) = @_;
993 my $defalt_classification_source =
994 C4
::Context
->preference('DefaultClassificationSource');
996 cn_source
=> $defalt_classification_source,
1000 $item_hash->{booksellerid
} = $quote->vendor_id;
1001 $item_hash->{price
} = $item_hash->{replacementprice
} = $item->price;
1002 $item_hash->{itype
} = $item->girfield('stock_category');
1003 $item_hash->{location
} = $item->girfield('collection_code');
1007 $item_hash->{itemcallnumber
} =
1008 $item->girfield('shelfmark')
1009 || $item->girfield('classification')
1010 || title_level_class
($item);
1012 my $branch = $item->girfield('branch');
1013 $item_hash->{holdingbranch
} = $item_hash->{homebranch
} = $branch;
1026 Module exporting subroutines used in EDI processing for Koha
1030 Subroutines called by batch processing to handle Edifact
1031 messages of various types and related utilities
1035 These routines should really be methods of some object.
1036 get_edifact_ean is a stopgap which should be replaced
1040 =head2 process_quote
1042 process_quote(quote_message);
1044 passed a message object for a quote, parses it creating an order basket
1045 and orderlines in the database
1046 updates the message's status to received in the database and adds the
1049 =head2 process_invoice
1051 process_invoice(invoice_message)
1053 passed a message object for an invoice, add the contained invoices
1054 and update the orderlines referred to in the invoice
1055 As an Edifact invoice is in effect a despatch note this receipts the
1056 appropriate quantities in the orders
1058 no meaningful return value
1060 =head2 process_ordrsp
1062 process_ordrsp(ordrsp_message)
1064 passed a message object for a supplier response, process the contents
1065 If an orderline is cancelled cancel the corresponding orderline in koha
1066 otherwise record the supplier message against it
1068 no meaningful return value
1070 =head2 create_edi_order
1072 create_edi_order( { parameter_hashref } )
1074 parameters must include basketno and ean
1076 branchcode can optionally be passed
1078 returns 1 on success undef otherwise
1080 if the parameter noingest is set the formatted order is returned
1081 and not saved in the database. This functionality is intended for debugging only
1083 =head2 receipt_items
1085 receipt_items( schema_obj, invoice_line, ordernumber)
1087 receipts the items recorded on this invoice line
1089 no meaningful return
1091 =head2 transfer_items
1093 transfer_items(schema, invoice_line, originating_order, receiving_order)
1095 Transfer the items covered by this invoice line from their original
1096 order to another order recording the partial fulfillment of the original
1099 no meaningful return
1101 =head2 get_edifact_ean
1103 $ean = get_edifact_ean();
1105 routine to return the ean.
1109 quote_item(lineitem, quote_message);
1111 Called by process_quote to handle an individual lineitem
1112 Generate the biblios and items if required and orderline linking to them
1114 Returns 1 on success undef on error
1116 Most usual cause of error is a line with no or incorrect budget codes
1117 which woild cause order creation to abort
1118 If other correct lines exist these are processed and the erroneous line os logged
1120 =head2 title_level_class
1122 classmark = title_level_class(edi_item)
1124 Trys to return a title level classmark from a quote message line
1125 Will return a dewey or lcc classmark if one exists according to the
1126 value in DefaultClassificationSource syspref
1128 If unable to returns the shelfmark or classification from the GIR segment
1130 If all else fails returns empty string
1132 =head2 _create_bib_from_quote
1134 marc_record_obj = _create_bib_from_quote(lineitem, quote)
1136 Returns a MARC::Record object based on the info in the quote's lineitem
1138 =head2 _create_item_from_quote
1140 item_hashref = _create_item_from_quote( lineitem, quote)
1142 returns a hashref representing the item fields specified in the quote
1144 =head2 _get_invoiced_price
1146 _get_invoiced_price(line_object)
1148 Returns the net price or an equivalent calculated from line cost / qty
1150 =head2 _discounted_price
1152 ecost = _discounted_price(discount, item_price)
1154 utility subroutine to return a price calculated from the
1155 vendors discount and quoted price
1157 =head2 _check_for_existing_bib
1159 (biblionumber, biblioitemnumber) = _check_for_existing_bib(isbn_or_ean)
1161 passed an isbn or ean attempts to locate a match bib
1162 On success returns biblionumber and biblioitemnumber
1163 On failure returns undefined/an empty list
1167 b = _get_budget(schema_obj, budget_code)
1169 Returns the Aqbudget object for the active budget given the passed budget_code
1170 or undefined if one does not exist
1174 Colin Campbell <colin.campbell@ptfs-europe.com>
1179 Copyright 2014,2015 PTFS-Europe Ltd
1180 This program is free software, You may redistribute it under
1181 under the terms of the GNU General Public License