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;
42 qw( process_quote process_invoice process_ordrsp create_edi_order get_edifact_ean );
44 sub create_edi_order {
45 my $parameters = shift;
46 my $basketno = $parameters->{basketno};
47 my $ean = $parameters->{ean};
48 my $branchcode = $parameters->{branchcode};
49 my $noingest = $parameters->{noingest};
50 if ( !$basketno || !$ean ) {
51 carp 'create_edi_order called with no basketno or ean';
55 my $schema = Koha::Database->new()->schema();
57 my @orderlines = $schema->resultset('Aqorder')->search(
59 basketno => $basketno,
65 carp "No orderlines for basket $basketno";
69 my $vendor = $schema->resultset('VendorEdiAccount')->search(
71 vendor_id => $orderlines[0]->basketno->booksellerid->id,
75 my $ean_search_keys = { ean => $ean, };
77 $ean_search_keys->{branchcode} = $branchcode;
80 $schema->resultset('EdifactEan')->search($ean_search_keys)->single;
82 my $dbh = C4::Context->dbh;
83 my $arr_ref = $dbh->selectcol_arrayref(
84 'select id from edifact_messages where basketno = ? and message_type = \'QUOTE\'',
87 my $response = @{$arr_ref} ? 1 : 0;
89 my $edifact_order_params = {
90 orderlines => \@orderlines,
93 is_response => $response,
97 if ( $vendor->plugin ) {
98 $edifact = Koha::Plugins::Handler->run(
100 class => $vendor->plugin,
101 method => 'edifact_order',
103 params => $edifact_order_params,
109 $edifact = Koha::Edifact::Order->new($edifact_order_params);
112 return unless $edifact;
114 my $order_file = $edifact->encode();
118 my $m = unidecode($order_file); # remove diacritics and non-latin chars
119 if ($noingest) { # allows scripts to produce test files
123 message_type => 'ORDERS',
125 vendor_id => $vendor->vendor_id,
127 basketno => $basketno,
128 filename => $edifact->filename(),
129 transfer_date => $edifact->msg_date_string(),
130 edi_acct => $vendor->id,
133 $schema->resultset('EdifactMessage')->create($order);
141 my $response_message = shift;
142 $response_message->status('processing');
143 $response_message->update;
144 my $schema = Koha::Database->new()->schema();
145 my $logger = Log::Log4perl->get_logger();
148 Koha::Edifact->new( { transmission => $response_message->raw_msg, } );
149 my $messages = $edi->message_array();
151 if ( @{$messages} ) {
152 foreach my $msg ( @{$messages} ) {
153 my $lines = $msg->lineitems();
154 foreach my $line ( @{$lines} ) {
155 my $ordernumber = $line->ordernumber();
157 # action cancelled:change_requested:no_action:accepted:not_found:recorded
158 my $action = $line->action_notification();
159 if ( $action eq 'cancelled' ) {
160 my $reason = $line->coded_orderline_text();
163 ordernumber => $ordernumber,
164 cancellationreason => $reason,
165 orderstatus => 'cancelled',
166 datecancellationprinted => DateTime->now()->ymd(),
170 else { # record order as due with possible further info
172 my $report = $line->coded_orderline_text();
173 my $date_avail = $line->availability_date();
176 $report .= " Available: $date_avail";
180 ordernumber => $ordernumber,
181 suppliers_report => $report,
189 $response_message->status('received');
190 $response_message->update;
194 sub process_invoice {
195 my $invoice_message = shift;
196 $invoice_message->status('processing');
197 $invoice_message->update;
198 my $schema = Koha::Database->new()->schema();
199 my $logger = Log::Log4perl->get_logger();
202 my $plugin = $invoice_message->edi_acct()->plugin();
205 $edi_plugin = Koha::Plugins::Handler->run(
210 invoice_message => $invoice_message,
211 transmission => $invoice_message->raw_msg,
217 my $edi = $edi_plugin ||
218 Koha::Edifact->new( { transmission => $invoice_message->raw_msg, } );
220 my $messages = $edi->message_array();
222 if ( @{$messages} ) {
224 # BGM contains an invoice number
225 foreach my $msg ( @{$messages} ) {
226 my $invoicenumber = $msg->docmsg_number();
227 my $shipmentcharge = $msg->shipment_charge();
228 my $msg_date = $msg->message_date;
229 my $tax_date = $msg->tax_point_date;
230 if ( !defined $tax_date || $tax_date !~ m/^\d{8}/xms ) {
231 $tax_date = $msg_date;
234 my $vendor_ean = $msg->supplier_ean;
235 if ( !defined $vendor_acct || $vendor_ean ne $vendor_acct->san ) {
236 $vendor_acct = $schema->resultset('VendorEdiAccount')->search(
242 if ( !$vendor_acct ) {
244 "Cannot find vendor with ean $vendor_ean for invoice $invoicenumber in $invoice_message->filename";
247 $invoice_message->edi_acct( $vendor_acct->id );
248 $logger->trace("Adding invoice:$invoicenumber");
249 my $new_invoice = $schema->resultset('Aqinvoice')->create(
251 invoicenumber => $invoicenumber,
252 booksellerid => $invoice_message->vendor_id,
253 shipmentdate => $msg_date,
254 billingdate => $tax_date,
255 shipmentcost => $shipmentcharge,
256 shipmentcost_budgetid => $vendor_acct->shipment_budget,
257 message_id => $invoice_message->id,
260 my $invoiceid = $new_invoice->invoiceid;
261 $logger->trace("Added as invoiceno :$invoiceid");
262 my $lines = $msg->lineitems();
264 foreach my $line ( @{$lines} ) {
265 my $ordernumber = $line->ordernumber;
266 $logger->trace( "Receipting order:$ordernumber Qty: ",
269 my $order = $schema->resultset('Aqorder')->find($ordernumber);
271 # ModReceiveOrder does not validate that $ordernumber exists validate here
275 my $s = $schema->resultset('Suggestion')->search(
277 biblionumber => $order->biblionumber->biblionumber,
283 suggestionid => $s->suggestionid,
284 STATUS => 'AVAILABLE',
289 my $price = _get_invoiced_price($line);
291 if ( $order->quantity > $line->quantity ) {
292 my $ordered = $order->quantity;
295 $order->orderstatus('partial');
296 $order->quantity( $ordered - $line->quantity );
298 my $received_order = $order->copy(
300 ordernumber => undef,
301 quantity => $line->quantity,
302 quantityreceived => $line->quantity,
303 orderstatus => 'complete',
305 invoiceid => $invoiceid,
306 datereceived => $msg_date,
309 transfer_items( $schema, $line, $order,
311 receipt_items( $schema, $line,
312 $received_order->ordernumber );
314 else { # simple receipt all copies on order
315 $order->quantityreceived( $line->quantity );
316 $order->datereceived($msg_date);
317 $order->invoiceid($invoiceid);
318 $order->unitprice($price);
319 $order->orderstatus('complete');
321 receipt_items( $schema, $line, $ordernumber );
326 "No order found for $ordernumber Invoice:$invoicenumber"
336 $invoice_message->status('received');
337 $invoice_message->update; # status and basketno link
341 sub _get_invoiced_price {
343 my $price = $line->price_net;
344 if ( !defined $price ) { # no net price so generate it from lineitem amount
345 $price = $line->amt_lineitem;
346 if ( $price and $line->quantity > 1 ) {
347 $price /= $line->quantity; # div line cost by qty
354 my ( $schema, $inv_line, $ordernumber ) = @_;
355 my $logger = Log::Log4perl->get_logger();
356 my $quantity = $inv_line->quantity;
358 # itemnumber is not a foreign key ??? makes this a bit cumbersome
359 my @item_links = $schema->resultset('AqordersItem')->search(
361 ordernumber => $ordernumber,
365 foreach my $ilink (@item_links) {
366 my $item = $schema->resultset('Item')->find( $ilink->itemnumber );
368 my $i = $ilink->itemnumber;
370 "Cannot find aqorder item for $i :Order:$ordernumber");
373 my $b = $item->homebranch->branchcode;
374 if ( !exists $branch_map{$b} ) {
375 $branch_map{$b} = [];
377 push @{ $branch_map{$b} }, $item;
379 my $gir_occurrence = 0;
380 while ( $gir_occurrence < $quantity ) {
381 my $branch = $inv_line->girfield( 'branch', $gir_occurrence );
382 my $item = shift @{ $branch_map{$branch} };
384 my $barcode = $inv_line->girfield( 'barcode', $gir_occurrence );
385 if ( $barcode && !$item->barcode ) {
386 my $rs = $schema->resultset('Item')->search(
391 if ( $rs->count > 0 ) {
392 $logger->warn("Barcode $barcode is a duplicate");
396 $logger->trace("Adding barcode $barcode");
397 $item->barcode($barcode);
404 $logger->warn("Unmatched item at branch:$branch");
413 my ( $schema, $inv_line, $order_from, $order_to ) = @_;
415 # Transfer x items from the orig order to a completed partial order
416 my $quantity = $inv_line->quantity;
418 my %mapped_by_branch;
419 while ( $gocc < $quantity ) {
420 my $branch = $inv_line->girfield( 'branch', $gocc );
421 if ( !exists $mapped_by_branch{$branch} ) {
422 $mapped_by_branch{$branch} = 1;
425 $mapped_by_branch{$branch}++;
429 my $logger = Log::Log4perl->get_logger();
430 my $o1 = $order_from->ordernumber;
431 my $o2 = $order_to->ordernumber;
432 $logger->warn("transferring $quantity copies from order $o1 to order $o2");
434 my @item_links = $schema->resultset('AqordersItem')->search(
436 ordernumber => $order_from->ordernumber,
439 foreach my $ilink (@item_links) {
440 my $ino = $ilink->itemnumber;
441 my $item = $schema->resultset('Item')->find( $ilink->itemnumber );
442 my $i_branch = $item->homebranch;
443 if ( exists $mapped_by_branch{$i_branch}
444 && $mapped_by_branch{$i_branch} > 0 )
446 $ilink->ordernumber( $order_to->ordernumber );
449 --$mapped_by_branch{$i_branch};
450 $logger->warn("Transferred item $item");
453 $logger->warn("Skipped item $item");
455 if ( $quantity < 1 ) {
466 $quote->status('processing');
469 my $edi = Koha::Edifact->new( { transmission => $quote->raw_msg, } );
471 my $messages = $edi->message_array();
472 my $process_errors = 0;
473 my $logger = Log::Log4perl->get_logger();
474 my $schema = Koha::Database->new()->schema();
475 my $message_count = 0;
476 my @added_baskets; # if auto & multiple baskets need to order all
478 if ( @{$messages} && $quote->vendor_id ) {
479 foreach my $msg ( @{$messages} ) {
482 NewBasket( $quote->vendor_id, 0, $quote->filename, q{},
484 push @added_baskets, $basketno;
485 if ( $message_count > 1 ) {
486 my $m_filename = $quote->filename;
487 $m_filename .= "_$message_count";
488 $schema->resultset('EdifactMessage')->create(
490 message_type => $quote->message_type,
491 transfer_date => $quote->transfer_date,
492 vendor_id => $quote->vendor_id,
493 edi_acct => $quote->edi_acct,
495 basketno => $basketno,
497 filename => $m_filename,
502 $quote->basketno($basketno);
504 $logger->trace("Created basket :$basketno");
505 my $items = $msg->lineitems();
506 my $refnum = $msg->message_refno;
508 for my $item ( @{$items} ) {
509 if ( !quote_item( $item, $quote, $basketno ) ) {
515 my $status = 'received';
516 if ($process_errors) {
520 $quote->status($status);
521 $quote->update; # status and basketno link
522 # Do we automatically generate orders for this vendor
523 my $v = $schema->resultset('VendorEdiAccount')->search(
525 vendor_id => $quote->vendor_id,
528 if ( $v->auto_orders ) {
529 for my $b (@added_baskets) {
544 my ( $item, $quote, $basketno ) = @_;
546 my $schema = Koha::Database->new()->schema();
548 # create biblio record
549 my $logger = Log::Log4perl->get_logger();
551 $logger->error('Skipping order creation no basketno');
554 $logger->trace( 'Checking db for matches with ', $item->item_number_id() );
555 my $bib = _check_for_existing_bib( $item->item_number_id() );
556 if ( !defined $bib ) {
558 my $bib_record = _create_bib_from_quote( $item, $quote );
559 ( $bib->{biblionumber}, $bib->{biblioitemnumber} ) =
560 AddBiblio( $bib_record, q{} );
561 $logger->trace("New biblio added $bib->{biblionumber}");
564 $logger->trace("Match found: $bib->{biblionumber}");
567 # Create an orderline
568 my $order_note = $item->{orderline_free_text};
570 my $order_quantity = $item->quantity();
571 my $gir_count = $item->number_of_girs();
572 $order_quantity ||= 1; # quantity not necessarily present
573 if ( $gir_count > 1 ) {
574 if ( $gir_count != $order_quantity ) {
576 "Order for $order_quantity items, $gir_count segments present");
578 $order_quantity = 1; # attempts to create an orderline for each gir
580 my $vendor = $schema->resultset('Aqbookseller')->find( $quote->vendor_id );
582 # database definitions should set some of these defaults but dont
584 biblionumber => $bib->{biblionumber},
585 entrydate => DateTime->now( time_zone => 'local' )->ymd(),
586 basketno => $basketno,
587 listprice => $item->price,
588 quantity => $order_quantity,
589 quantityreceived => 0,
590 order_vendornote => q{},
591 order_internalnote => $order_note,
593 ecost => _discounted_price( $quote->vendor->discount, $item->price ),
597 currency => $vendor->listprice->currency,
600 # suppliers references
601 if ( $item->reference() ) {
602 $order_hash->{suppliers_reference_number} = $item->reference;
603 $order_hash->{suppliers_reference_qualifier} = 'QLI';
605 elsif ( $item->orderline_reference_number() ) {
606 $order_hash->{suppliers_reference_number} =
607 $item->orderline_reference_number;
608 $order_hash->{suppliers_reference_qualifier} = 'SLI';
610 if ( $item->item_number_id ) { # suppliers ean
611 $order_hash->{line_item_id} = $item->item_number_id;
614 if ( $item->girfield('servicing_instruction') ) {
618 while ( $si = $item->girfield( 'servicing_instruction', $occ ) ) {
625 $order_hash->{order_vendornote} = $txt;
628 if ( $item->internal_notes() ) {
629 if ( $order_hash->{order_internalnote} ) { # more than ''
630 $order_hash->{order_internalnote} .= q{ };
632 $order_hash->{order_internalnote} .= $item->internal_notes;
635 my $budget = _get_budget( $schema, $item->girfield('fund_allocation') );
639 if ( $item->quantity > 1 ) {
640 carp 'Skipping line with no budget info';
641 $logger->trace('girfield skipped for invalid budget');
645 carp 'Skipping line with no budget info';
646 $logger->trace('orderline skipped for invalid budget');
656 $order_hash->{budget_id} = $budget->budget_id;
657 my $first_order = $schema->resultset('Aqorder')->create($order_hash);
658 my $o = $first_order->ordernumber();
659 $logger->trace("Order created :$o");
661 # should be done by database settings
662 $first_order->parent_ordernumber( $first_order->ordernumber() );
663 $first_order->update();
665 # add to $budgets to prevent duplicate orderlines
666 $budgets{ $budget->budget_id } = '1';
668 # record ordernumber against budget
669 $ordernumber{ $budget->budget_id } = $o;
671 if ( C4::Context->preference('AcqCreateItem') eq 'ordering' ) {
672 $item_hash = _create_item_from_quote( $item, $quote );
675 while ( $created < $order_quantity ) {
677 ( $bib->{biblionumber}, $bib->{biblioitemnumber}, $itemnumber )
678 = AddItem( $item_hash, $bib->{biblionumber} );
679 $logger->trace("Added item:$itemnumber");
680 $schema->resultset('AqordersItem')->create(
682 ordernumber => $first_order->ordernumber,
683 itemnumber => $itemnumber,
691 if ( $order_quantity == 1 && $item->quantity > 1 ) {
692 my $occurrence = 1; # occ zero already added
693 while ( $occurrence < $item->quantity ) {
696 $budget = _get_budget( $schema,
697 $item->girfield( 'fund_allocation', $occurrence ) );
701 $item->girfield( 'fund_allocation', $occurrence );
702 carp 'Skipping line with no budget info';
704 "girfield skipped for invalid budget:$bad_budget");
705 ++$occurrence; ## lets look at the next one not this one again
709 # add orderline for NEW budget in $budgets
710 if ( !exists $budgets{ $budget->budget_id } ) {
712 # $order_hash->{quantity} = 1; by default above
713 # we should handle both 1:1 GIR & 1:n GIR (with LQT values) here
715 $order_hash->{budget_id} = $budget->budget_id;
718 $schema->resultset('Aqorder')->create($order_hash);
719 my $o = $new_order->ordernumber();
720 $logger->trace("Order created :$o");
722 # should be done by database settings
723 $new_order->parent_ordernumber( $new_order->ordernumber() );
724 $new_order->update();
726 # add to $budgets to prevent duplicate orderlines
727 $budgets{ $budget->budget_id } = '1';
729 # record ordernumber against budget
730 $ordernumber{ $budget->budget_id } = $o;
732 if ( C4::Context->preference('AcqCreateItem') eq 'ordering' ) {
733 if ( !defined $item_hash ) {
734 $item_hash = _create_item_from_quote( $item, $quote );
738 $item->girfield( 'stock_category', $occurrence ),
740 $item->girfield( 'collection_code', $occurrence ),
742 $item->girfield( 'shelfmark', $occurrence )
743 || $item->girfield( 'classification', $occurrence )
744 || title_level_class($item),
746 $item->girfield( 'branch', $occurrence ),
747 homebranch => $item->girfield( 'branch', $occurrence ),
749 if ( $new_item->{itype} ) {
750 $item_hash->{itype} = $new_item->{itype};
752 if ( $new_item->{location} ) {
753 $item_hash->{location} = $new_item->{location};
755 if ( $new_item->{itemcallnumber} ) {
756 $item_hash->{itemcallnumber} =
757 $new_item->{itemcallnumber};
759 if ( $new_item->{holdingbranch} ) {
760 $item_hash->{holdingbranch} =
761 $new_item->{holdingbranch};
763 if ( $new_item->{homebranch} ) {
764 $item_hash->{homebranch} = $new_item->{homebranch};
768 ( undef, undef, $itemnumber ) =
769 AddItem( $item_hash, $bib->{biblionumber} );
770 $logger->trace("New item $itemnumber added");
771 $schema->resultset('AqordersItem')->create(
773 ordernumber => $new_order->ordernumber,
774 itemnumber => $itemnumber,
782 # increment quantity in orderline for EXISTING budget in $budgets
784 my $row = $schema->resultset('Aqorder')->find(
786 ordernumber => $ordernumber{ $budget->budget_id }
790 my $qty = $row->quantity;
799 if ( C4::Context->preference('AcqCreateItem') eq 'ordering' ) {
804 price => $item->price,
805 replacementprice => $item->price,
807 $item->girfield( 'stock_category', $occurrence ),
809 $item->girfield( 'collection_code', $occurrence ),
811 $item->girfield( 'shelfmark', $occurrence )
812 || $item->girfield( 'classification', $occurrence )
813 || $item_hash->{itemcallnumber},
815 $item->girfield( 'branch', $occurrence ),
816 homebranch => $item->girfield( 'branch', $occurrence ),
819 ( undef, undef, $itemnumber ) =
820 AddItem( $new_item, $bib->{biblionumber} );
821 $logger->trace("New item $itemnumber added");
822 $schema->resultset('AqordersItem')->create(
824 ordernumber => $ordernumber{ $budget->budget_id },
825 itemnumber => $itemnumber,
838 sub get_edifact_ean {
840 my $dbh = C4::Context->dbh;
842 my $eans = $dbh->selectcol_arrayref('select ean from edifact_ean');
847 # We should not need to have a routine to do this here
848 sub _discounted_price {
849 my ( $discount, $price ) = @_;
850 return $price - ( ( $discount * $price ) / 100 );
853 sub _check_for_existing_bib {
856 my $search_isbn = $isbn;
857 $search_isbn =~ s/^\s*/%/xms;
858 $search_isbn =~ s/\s*$/%/xms;
859 my $dbh = C4::Context->dbh;
860 my $sth = $dbh->prepare(
861 'select biblionumber, biblioitemnumber from biblioitems where isbn like ?',
864 $dbh->selectall_arrayref( $sth, { Slice => {} }, $search_isbn );
865 if ( @{$tuple_arr} ) {
866 return $tuple_arr->[0];
868 elsif ( length($isbn) == 13 && $isbn !~ /^97[89]/ ) {
869 my $tarr = $dbh->selectall_arrayref(
870 'select biblionumber, biblioitemnumber from biblioitems where ean = ?',
881 if ( $isbn =~ m/(\d{13})/xms ) {
882 my $b_isbn = Business::ISBN->new($1);
883 if ( $b_isbn && $b_isbn->is_valid ) {
884 $search_isbn = $b_isbn->as_isbn10->as_string( [] );
888 elsif ( $isbn =~ m/(\d{9}[xX]|\d{10})/xms ) {
889 my $b_isbn = Business::ISBN->new($1);
890 if ( $b_isbn && $b_isbn->is_valid ) {
891 $search_isbn = $b_isbn->as_isbn13->as_string( [] );
896 $search_isbn = "%$search_isbn%";
898 $dbh->selectall_arrayref( $sth, { Slice => {} }, $search_isbn );
899 if ( @{$tuple_arr} ) {
900 return $tuple_arr->[0];
907 # returns a budget obj or undef
908 # fact we need this shows what a mess Acq API is
910 my ( $schema, $budget_code ) = @_;
911 my $period_rs = $schema->resultset('Aqbudgetperiod')->search(
913 budget_period_active => 1,
917 # db does not ensure budget code is unque
918 return $schema->resultset('Aqbudget')->single(
920 budget_code => $budget_code,
922 { -in => $period_rs->get_column('budget_period_id')->as_query },
927 # try to get title level classification from incoming quote
928 sub title_level_class {
931 my $default_scheme = C4::Context->preference('DefaultClassificationSource');
932 if ( $default_scheme eq 'ddc' ) {
933 $class = $item->dewey_class();
935 elsif ( $default_scheme eq 'lcc' ) {
936 $class = $item->lc_class();
940 $item->girfield('shelfmark')
941 || $item->girfield('classification')
947 sub _create_bib_from_quote {
949 #TBD we should flag this for updating from an external source
950 #As biblio (&biblioitems) has no candidates flag in order
951 my ( $item, $quote ) = @_;
952 my $itemid = $item->item_number_id;
953 my $defalt_classification_source =
954 C4::Context->preference('DefaultClassificationSource');
956 'biblioitems.cn_source' => $defalt_classification_source,
957 'items.cn_source' => $defalt_classification_source,
958 'items.notforloan' => -1,
959 'items.cn_sort' => q{},
961 $bib_hash->{'biblio.seriestitle'} = $item->series;
963 $bib_hash->{'biblioitems.publishercode'} = $item->publisher;
964 $bib_hash->{'biblioitems.publicationyear'} =
965 $bib_hash->{'biblio.copyrightdate'} = $item->publication_date;
967 $bib_hash->{'biblio.title'} = $item->title;
968 $bib_hash->{'biblio.author'} = $item->author;
969 $bib_hash->{'biblioitems.isbn'} = $item->item_number_id;
970 $bib_hash->{'biblioitems.itemtype'} = $item->girfield('stock_category');
972 # If we have a 13 digit id we are assuming its an ean
973 # (it may also be an isbn or issn)
974 if ( $itemid =~ /^\d{13}$/ ) {
975 $bib_hash->{'biblioitems.ean'} = $itemid;
976 if ( $itemid =~ /^977/ ) {
977 $bib_hash->{'biblioitems.issn'} = $itemid;
980 for my $key ( keys %{$bib_hash} ) {
981 if ( !defined $bib_hash->{$key} ) {
982 delete $bib_hash->{$key};
985 return TransformKohaToMarc($bib_hash);
989 sub _create_item_from_quote {
990 my ( $item, $quote ) = @_;
991 my $defalt_classification_source =
992 C4::Context->preference('DefaultClassificationSource');
994 cn_source => $defalt_classification_source,
998 $item_hash->{booksellerid} = $quote->vendor_id;
999 $item_hash->{price} = $item_hash->{replacementprice} = $item->price;
1000 $item_hash->{itype} = $item->girfield('stock_category');
1001 $item_hash->{location} = $item->girfield('collection_code');
1005 $item_hash->{itemcallnumber} =
1006 $item->girfield('shelfmark')
1007 || $item->girfield('classification')
1008 || title_level_class($item);
1010 my $branch = $item->girfield('branch');
1011 $item_hash->{holdingbranch} = $item_hash->{homebranch} = $branch;
1024 Module exporting subroutines used in EDI processing for Koha
1028 Subroutines called by batch processing to handle Edifact
1029 messages of various types and related utilities
1033 These routines should really be methods of some object.
1034 get_edifact_ean is a stopgap which should be replaced
1038 =head2 process_quote
1040 process_quote(quote_message);
1042 passed a message object for a quote, parses it creating an order basket
1043 and orderlines in the database
1044 updates the message's status to received in the database and adds the
1047 =head2 process_invoice
1049 process_invoice(invoice_message)
1051 passed a message object for an invoice, add the contained invoices
1052 and update the orderlines referred to in the invoice
1053 As an Edifact invoice is in effect a despatch note this receipts the
1054 appropriate quantities in the orders
1056 no meaningful return value
1058 =head2 process_ordrsp
1060 process_ordrsp(ordrsp_message)
1062 passed a message object for a supplier response, process the contents
1063 If an orderline is cancelled cancel the corresponding orderline in koha
1064 otherwise record the supplier message against it
1066 no meaningful return value
1068 =head2 create_edi_order
1070 create_edi_order( { parameter_hashref } )
1072 parameters must include basketno and ean
1074 branchcode can optionally be passed
1076 returns 1 on success undef otherwise
1078 if the parameter noingest is set the formatted order is returned
1079 and not saved in the database. This functionality is intended for debugging only
1081 =head2 receipt_items
1083 receipt_items( schema_obj, invoice_line, ordernumber)
1085 receipts the items recorded on this invoice line
1087 no meaningful return
1089 =head2 transfer_items
1091 transfer_items(schema, invoice_line, originating_order, receiving_order)
1093 Transfer the items covered by this invoice line from their original
1094 order to another order recording the partial fulfillment of the original
1097 no meaningful return
1099 =head2 get_edifact_ean
1101 $ean = get_edifact_ean();
1103 routine to return the ean.
1107 quote_item(lineitem, quote_message);
1109 Called by process_quote to handle an individual lineitem
1110 Generate the biblios and items if required and orderline linking to them
1112 Returns 1 on success undef on error
1114 Most usual cause of error is a line with no or incorrect budget codes
1115 which woild cause order creation to abort
1116 If other correct lines exist these are processed and the erroneous line os logged
1118 =head2 title_level_class
1120 classmark = title_level_class(edi_item)
1122 Trys to return a title level classmark from a quote message line
1123 Will return a dewey or lcc classmark if one exists according to the
1124 value in DefaultClassificationSource syspref
1126 If unable to returns the shelfmark or classification from the GIR segment
1128 If all else fails returns empty string
1130 =head2 _create_bib_from_quote
1132 marc_record_obj = _create_bib_from_quote(lineitem, quote)
1134 Returns a MARC::Record object based on the info in the quote's lineitem
1136 =head2 _create_item_from_quote
1138 item_hashref = _create_item_from_quote( lineitem, quote)
1140 returns a hashref representing the item fields specified in the quote
1142 =head2 _get_invoiced_price
1144 _get_invoiced_price(line_object)
1146 Returns the net price or an equivalent calculated from line cost / qty
1148 =head2 _discounted_price
1150 ecost = _discounted_price(discount, item_price)
1152 utility subroutine to return a price calculated from the
1153 vendors discount and quoted price
1155 =head2 _check_for_existing_bib
1157 (biblionumber, biblioitemnumber) = _check_for_existing_bib(isbn_or_ean)
1159 passed an isbn or ean attempts to locate a match bib
1160 On success returns biblionumber and biblioitemnumber
1161 On failure returns undefined/an empty list
1165 b = _get_budget(schema_obj, budget_code)
1167 Returns the Aqbudget object for the active budget given the passed budget_code
1168 or undefined if one does not exist
1172 Colin Campbell <colin.campbell@ptfs-europe.com>
1177 Copyright 2014,2015 PTFS-Europe Ltd
1178 This program is free software, You may redistribute it under
1179 under the terms of the GNU General Public License