From c81f598d801d7251ea22e3eb1bbbba2beb4ee085 Mon Sep 17 00:00:00 2001 From: Colin Campbell Date: Thu, 20 Sep 2012 16:05:54 +0100 Subject: [PATCH] Bug 7736: EDI Edifact quote and order functionality This is a patch brining together the original work by Mark Gavillet and the subsequent patches by Mark, Martin Renvoize and myself It contains the code as currently runnng in production --- C4/EDI.pm | 1095 ++++++++++++++++++++ acqui/basket.pl | 12 + admin/edi-accounts.pl | 71 ++ admin/edi-edit.pl | 73 ++ installer/data/mysql/atomicupdate/edifact.sql | 27 + .../intranet-tmpl/prog/en/includes/admin-menu.inc | 3 +- .../intranet-tmpl/prog/en/includes/tools-menu.inc | 5 +- .../intranet-tmpl/prog/en/modules/acqui/basket.tt | 11 +- .../prog/en/modules/admin/admin-home.tt | 2 + .../prog/en/modules/admin/edi-accounts.tt | 46 + .../prog/en/modules/admin/edi-edit.tt | 102 ++ .../intranet-tmpl/prog/en/modules/tools/edi.tt | 54 + .../prog/en/modules/tools/tools-home.tt | 5 + misc/cronjobs/clean_edifiles.pl | 43 + misc/cronjobs/edifact_order_ftp_transfer.pl | 132 +++ misc/cronjobs/send_queued_edi_orders.pl | 28 + tools/edi.pl | 43 + 17 files changed, 1749 insertions(+), 3 deletions(-) create mode 100644 C4/EDI.pm create mode 100755 admin/edi-accounts.pl create mode 100755 admin/edi-edit.pl create mode 100644 installer/data/mysql/atomicupdate/edifact.sql create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-accounts.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-edit.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/edi.tt create mode 100755 misc/cronjobs/clean_edifiles.pl create mode 100755 misc/cronjobs/edifact_order_ftp_transfer.pl create mode 100755 misc/cronjobs/send_queued_edi_orders.pl create mode 100755 tools/edi.pl diff --git a/C4/EDI.pm b/C4/EDI.pm new file mode 100644 index 0000000..a948891 --- /dev/null +++ b/C4/EDI.pm @@ -0,0 +1,1095 @@ +package C4::EDI; + +# Copyright 2011 Mark Gavillet +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Context; +use C4::Acquisition; +use Net::FTP; +use Business::Edifact::Interchange; +use C4::Biblio; +use C4::Items; +use Business::ISBN; +use Carp; +use parent qw(Exporter); + +our $VERSION = 3.09.00.53; +our @EXPORT = qw( + GetEDIAccounts + GetEDIAccountDetails + CreateEDIDetails + UpdateEDIDetails + LogEDIFactOrder + LogEDIFactQuote + DeleteEDIDetails + GetVendorList + GetEDIfactMessageList + GetEDIFTPAccounts + LogEDITransaction + GetVendorSAN + CreateEDIOrder + SendEDIOrder + SendQueuedEDIOrders + ParseEDIQuote + GetDiscountedPrice + GetBudgetID + CheckOrderItemExists + GetBranchCode + string35escape + GetOrderItemInfo + CheckVendorFTPAccountExists +); + +=head1 NAME + +C4::EDI - Perl Module containing functions for Vendor EDI accounts and EDIfact messages + +=head1 VERSION + +Version 0.01 + +=head1 SYNOPSIS + +use C4::EDI; + +=head1 DESCRIPTION + +This module contains routines for adding, modifying and deleting EDI account details for vendors, interacting with vendor FTP sites to send/retrieve quote and order messages, formatting EDIfact orders, and parsing EDIfact quotes to baskets + +=head2 GetVendorList + +Returns a list of vendors from aqbooksellers to populate drop down select menu + +=cut + +sub GetVendorList { + my $dbh = C4::Context->dbh; + my $sth; + $sth = + $dbh->prepare("select id, name from aqbooksellers order by name asc"); + $sth->execute(); + my $vendorlist = $sth->fetchall_arrayref( {} ); + return $vendorlist; +} + +=head2 CreateEDIDetails + +Inserts a new EDI vendor FTP account + +=cut + +sub CreateEDIDetails { + my ( $provider, $description, $host, $user, $pass, $in_dir, $san ) = @_; + my $dbh = C4::Context->dbh; + my $sth; + if ($provider) { + $sth = $dbh->prepare( +"insert into vendor_edi_accounts (description, host, username, password, provider, in_dir, san) values (?,?,?,?,?,?,?)" + ); + $sth->execute( $description, $host, $user, + $pass, $provider, $in_dir, $san ); + } + return; +} + +=head2 GetEDIAccounts + +Returns all vendor FTP accounts + +=cut + +sub GetEDIAccounts { + my $dbh = C4::Context->dbh; + my $sth; + $sth = $dbh->prepare( +"select vendor_edi_accounts.id, aqbooksellers.id as providerid, aqbooksellers.name as vendor, vendor_edi_accounts.description, vendor_edi_accounts.last_activity from vendor_edi_accounts inner join aqbooksellers on vendor_edi_accounts.provider = aqbooksellers.id order by aqbooksellers.name asc" + ); + $sth->execute(); + my $ediaccounts = $sth->fetchall_arrayref( {} ); + return $ediaccounts; +} + +=head2 DeleteEDIDetails + +Remove a vendor's FTP account + +=cut + +sub DeleteEDIDetails { + my ($id) = @_; + my $dbh = C4::Context->dbh; + my $sth; + if ($id) { + $sth = $dbh->prepare("delete from vendor_edi_accounts where id=?"); + $sth->execute($id); + } + return; +} + +=head2 UpdateEDIDetails + +Update a vendor's FTP account + +=cut + +sub UpdateEDIDetails { + my ( $editid, $description, $host, $user, $pass, $provider, $in_dir, $san ) + = @_; + my $dbh = C4::Context->dbh; + if ($editid) { + my $sth = $dbh->prepare( +"update vendor_edi_accounts set description=?, host=?, username=?, password=?, provider=?, in_dir=?, san=? where id=?" + ); + $sth->execute( $description, $host, $user, $pass, $provider, $in_dir, + $san, $editid ); + } + return; +} + +=head2 LogEDIFactOrder + +Updates or inserts to the edifact_messages table when processing an order and assigns a status and basket number + +=cut + +sub LogEDIFactOrder { + my ( $provider, $status, $basketno ) = @_; + my $dbh = C4::Context->dbh; + my $key; + my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time); + $year += 1900; + $mon += 1; + my $date_sent = $year . '-' . $mon . "-$mday"; + my $sth = $dbh->prepare( +"select edifact_messages.key from edifact_messages where basketno=? and provider=?" + ); + $sth->execute( $basketno, $provider ); + + #my $key=$sth->fetchrow_array(); + while ( my @row = $sth->fetchrow_array() ) { + $key = $row[0]; + } + if ($key) { + $sth = $dbh->prepare( +"update edifact_messages set date_sent=?, status=? where edifact_messages.key=?" + ); + $sth->execute( $date_sent, $status, $key ); + } + else { + $sth = $dbh->prepare( +"insert into edifact_messages (message_type,date_sent,provider,status,basketno) values (?,?,?,?,?)" + ); + $sth->execute( 'ORDER', $date_sent, $provider, $status, $basketno ); + } + return; +} + +=head2 LogEDIFactOrder + +Updates or inserts to the edifact_messages table when processing a quote and assigns a status and basket number + +=cut + +sub LogEDIFactQuote { + my ( $provider, $status, $basketno, $key ) = @_; + my $dbh = C4::Context->dbh; + my $sth; + my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time); + $year = 1900 + $year; + $mon = 1 + $mon; + my $date_sent = $year . "-" . $mon . "-$mday"; + if ( $key != 0 ) { + $sth = $dbh->prepare( +"update edifact_messages set date_sent=?, status=?, basketno=? where edifact_messages.key=?" + ); + $sth->execute( $date_sent, $status, $basketno, $key ); + } + else { + $sth = $dbh->prepare( +"insert into edifact_messages (message_type,date_sent,provider,status,basketno) values (?,?,?,?,?)" + ); + $sth->execute( 'QUOTE', $date_sent, $provider, $status, $basketno ); + $key = + $dbh->last_insert_id( undef, undef, qw(edifact_messages key), undef ); + } + return $key; +} + +=head2 GetEDIAccountDetails + +Returns FTP account details for a given vendor + +=cut + +sub GetEDIAccountDetails { + my ($id) = @_; + my $dbh = C4::Context->dbh; + my $sth; + if ($id) { + $sth = $dbh->prepare("select * from vendor_edi_accounts where id=?"); + $sth->execute($id); + my $edi_details = $sth->fetchrow_hashref; + return $edi_details; + } + return; +} + +=head2 GetEDIfactMessageList + +Returns a list of edifact_messages that have been processed, including the type (quote/order) and status + +=cut + +sub GetEDIfactMessageList { + my $dbh = C4::Context->dbh; + my $sth; + $sth = $dbh->prepare( +"select edifact_messages.key, edifact_messages.message_type, DATE_FORMAT(edifact_messages.date_sent,'%d/%m/%Y') as date_sent, aqbooksellers.id as providerid, aqbooksellers.name as providername, edifact_messages.status, edifact_messages.basketno from edifact_messages inner join aqbooksellers on edifact_messages.provider = aqbooksellers.id order by edifact_messages.date_sent desc, edifact_messages.key desc" + ); + $sth->execute(); + my $messagelist = $sth->fetchall_arrayref( {} ); + return $messagelist; +} + +=head2 GetEDIFTPAccounts + +Returns all vendor FTP accounts. Used when retrieving quotes messages overnight + +=cut + +sub GetEDIFTPAccounts { + my $dbh = C4::Context->dbh; + my $sth; + $sth = $dbh->prepare( +"select id, host, username, password, provider, in_dir from vendor_edi_accounts order by id asc" + ); + $sth->execute(); + my $ftpaccounts = $sth->fetchall_arrayref( {} ); + return $ftpaccounts; +} + +=head2 LogEDITransaction + +Updates the timestamp for a given vendor FTP account whenever there is activity + +=cut + +sub LogEDITransaction { + my $id = shift; + my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time); + $year = 1900 + $year; + $mon = 1 + $mon; + my $datestamp = $year . "/" . $mon . "/$mday"; + my $dbh = C4::Context->dbh; + my $sth; + $sth = $dbh->prepare( + "update vendor_edi_accounts set last_activity=? where id=?"); + $sth->execute( $datestamp, $id ); + return; +} + +=head2 GetVendorSAN + +Returns the stored SAN number for a given vendor + +=cut + +sub GetVendorSAN { + my $booksellerid = shift; + my $dbh = C4::Context->dbh; + my $san; + my $sth = + $dbh->prepare("select san from vendor_edi_accounts where provider=?"); + $sth->execute($booksellerid); + while ( my @result = $sth->fetchrow_array() ) { + $san = $result[0]; + } + return $san; +} + +=head2 CreateEDIOrder + +Formats an EDIfact order message from a given basket and stores as a file on the server + +=cut + +sub CreateEDIOrder { + my ( $basketno, $booksellerid ) = @_; + my @datetime = localtime(time); + my $longyear = $datetime[5] + 1900; + my $shortyear = sprintf '%02d', $datetime[5] - 100; + my $date = sprintf '%02d%02d', $datetime[4] + 1, $datetime[3]; + my $hourmin = sprintf '%02d%02d', $datetime[2], $datetime[1]; + my $year = $datetime[5] - 100; + my $month = sprintf '%02d', $datetime[4] + 1; + my $linecount = 0; + my $filename = "ediorder_$basketno.CEP"; + my $exchange = int( rand(99999999999999) ); + my $ref = int( rand(99999999999999) ); + my $san = GetVendorSAN($booksellerid); + my $message_type = GetMessageType($basketno); + my $output_file = C4::Context->config('intranetdir'); + $output_file .= "/misc/edi_files/$filename"; + + open my $fh, '>', $output_file + or croak "Unable to create $output_file : $!"; + + print $fh "UNA:+.? '"; # print opening header + print $fh "UNB+UNOC:2+" + . C4::Context->preference("EDIfactEAN") + . ":14+$san:31B+$shortyear$date:$hourmin+" + . $exchange + . "++ORDERS+++EANCOM'" + ; # print identifying EANs/SANs, date/time, exchange reference number + print $fh "UNH+" . $ref + . "+ORDERS:D:96A:UN:EAN008'"; # print message reference number + + if ( $message_type eq 'QUOTE' ) { + print $fh "BGM+22V+" + . $basketno + . "+9'"; # print order number and quote confirmation ref + } + else { + print $fh "BGM+220+" . $basketno . "+9'"; # print order number + } + print $fh "DTM+137:$longyear$date:102'"; # print date of message + print $fh "NAD+BY+" + . C4::Context->preference("EDIfactEAN") + . "::9'"; # print buyer EAN + print $fh "NAD+SU+" . $san . "::31B'"; # print vendor SAN + print $fh "NAD+SU+" . $booksellerid . "::92'"; # print internal ID + + # get items from basket + my @results = GetOrders($basketno); + foreach my $item (@results) { + $linecount++; + my $price; + my $title = string35escape( escape( $item->{title} ) ); + my $author = string35escape( escape( $item->{author} ) ); + my $publisher = string35escape( escape( $item->{publishercode} ) ); + $price = sprintf "%.2f", $item->{listprice}; + my $isbn; + if ( length( $item->{isbn} ) == 10 + || substr( $item->{isbn}, 0, 3 ) eq "978" + || index( $item->{isbn}, "|" ) != -1 ) + { + $isbn = cleanisbn( $item->{isbn} ); + $isbn = Business::ISBN->new($isbn); + if ($isbn) { + if ( $isbn->is_valid ) { + $isbn = ( $isbn->as_isbn13 )->isbn; + } + else { + $isbn = "0"; + } + } + else { + $isbn = 0; + } + } + else { + $isbn = $item->{isbn}; + } + my $copyrightdate = escape( $item->{publicationyear} ); + my $quantity = escape( $item->{quantity} ); + my $ordernumber = escape( $item->{ordernumber} ); + my $notes; + if ( $item->{notes} ) { + $notes = $item->{notes}; + $notes =~ s/[\r\n]+//g; + $notes = string35escape( escape($notes) ); + } + + my ( $branchcode, $callnumber, $itype, $lsqccode, $fund ) = + GetOrderItemInfo( $item->{'ordernumber'} ); + $callnumber = escape($callnumber); + + print $fh "LIN+$linecount++" . $isbn . ":EN'"; # line number, isbn + print $fh "PIA+5+" . $isbn + . ":IB'"; # isbn as main product identification + print $fh "IMD+L+050+:::$title'"; # title + print $fh "IMD+L+009+:::$author'"; # full name of author + print $fh "IMD+L+109+:::$publisher'"; # publisher + print $fh "IMD+L+170+:::$copyrightdate'"; # date of publication + print $fh "IMD+L+220+:::O'"; # binding (e.g. PB) (O if not specified) + if ( $callnumber ne '' ) { + print $fh "IMD+L+230+:::$callnumber'"; # shelfmark + } + print $fh "QTY+21:$quantity'"; # quantity + if ( $message_type ne 'QUOTE' && $quantity > 1 ) { + print $fh "GIR+001+$quantity:LQT+$branchcode:LLO+$fund:LFN+" + ; # branchcode, fund code + } + else { + print $fh + "GIR+001+$branchcode:LLO+$fund:LFN+"; # branchcode, fund code + } + if ( $callnumber ne '' ) { + print $fh "$callnumber:LCL+"; # shelfmark + } + print $fh $itype . ":LST+$lsqccode:LSQ'"; # stock category, sequence + if ($notes) { + print $fh "FTX+LIN+++:::$notes'"; + } + ###REQUEST ORDERS TO REVISIT +#if ($message_type ne 'QUOTE') +#{ +# print $fh "FTX+LIN++$linecount:10B:28'"; # freetext ** used for request orders to denote priority (to revisit) +#} + print $fh "PRI+AAB:$price'"; # price per item + print $fh "CUX+2:GBP:9'"; # currency (GBP) + print $fh "RFF+LI:$ordernumber'"; # Local order number + if ( $message_type eq 'QUOTE' ) { + print $fh "RFF+QLI:" + . $item->{booksellerinvoicenumber} + . q{'}; # If QUOTE confirmation, include booksellerinvoicenumber + } + } + print $fh "UNS+S'"; # print summary section header + print $fh "CNT+2:$linecount'"; # print number of line items in the message + my $segments = ( ( $linecount * 13 ) + 9 ); + print $fh "UNT+$segments+" + . $ref . "'" + ; # No. of segments in message (UNH+UNT elements included, UNA, UNB, UNZ excluded) + # Message ref number + print $fh "UNZ+1+" . $exchange . "'\n"; # Exchange ref number + + close $fh; + + LogEDIFactOrder( $booksellerid, 'Queued', $basketno ); + + return $filename; + +} + +sub GetMessageType { + my $basketno = shift; + my $dbh = C4::Context->dbh; + my $sth; + my $message_type; + my @row; + $sth = $dbh->prepare( + "select message_type from edifact_messages where basketno=?"); + $sth->execute($basketno); + while ( @row = $sth->fetchrow_array() ) { + $message_type = $row[0]; + } + return $message_type; +} + +sub cleanisbn { + my $isbn = shift; + if ($isbn) { + my $i = index( $isbn, '(' ); + if ( $i > 1 ) { + $isbn = substr( $isbn, 0, ( $i - 1 ) ); + } + if ( index( $isbn, "|" ) != -1 ) { + my @isbns = split( /\|/, $isbn ); + $isbn = $isbns[0]; + + #print "0: ".$isbns[0]."\n"; + } + $isbn = escape($isbn); + $isbn =~ s/^\s+//; + $isbn =~ s/\s+$//; + return $isbn; + } + return; +} + +sub escape { + my $string = shift; + if ($string) { + $string =~ s/\?/\?\?/g; + $string =~ s/\'/\?\'/g; + $string =~ s/\:/\?\:/g; + $string =~ s/\+/\?\+/g; + return $string; + } + return; +} + +=head2 GetBranchCode + +Return branchcode for an order when formatting an EDIfact order message + +=cut + +sub GetBranchCode { + my $biblioitemnumber = shift; + my $dbh = C4::Context->dbh; + my $sth; + my $branchcode; + my @row; + $sth = + $dbh->prepare("select homebranch from items where biblioitemnumber=?"); + $sth->execute($biblioitemnumber); + while ( @row = $sth->fetchrow_array() ) { + $branchcode = $row[0]; + } + return $branchcode; +} + +=head2 SendEDIOrder + +Transfers an EDIfact order message to the relevant vendor's FTP site + +=cut + +sub SendEDIOrder { + my ( $basketno, $booksellerid ) = @_; + my $newerr; + my $result; + + # check edi order file exists + my $edi_files = C4::Context->config('intranetdir'); + $edi_files .= '/misc/edi_files/'; + if ( -e "${edi_files}ediorder_$basketno.CEP" ) { + my $dbh = C4::Context->dbh; + my $sth; + $sth = $dbh->prepare( +"select id, host, username, password, provider, in_dir from vendor_edi_accounts where provider=?" + ); + $sth->execute($booksellerid); + my $ftpaccount = $sth->fetchrow_hashref; + + #check vendor edi account exists + if ($ftpaccount) { + + # connect to ftp account + my $ftp = Net::FTP->new( $ftpaccount->{host}, Timeout => 10 ) + or $newerr = 1; + if ( !$newerr ) { + $newerr = 0; + + # login + $ftp->login( "$ftpaccount->{username}", + "$ftpaccount->{password}" ) + or $newerr = 1; + $ftp->quit if $newerr; + if ( !$newerr ) { + + # cd to directory + $ftp->cwd("$ftpaccount->{in_dir}") or $newerr = 1; + $ftp->quit if $newerr; + + # put file + if ( !$newerr ) { + $newerr = 0; + $ftp->put("${edi_files}ediorder_$basketno.CEP") + or $newerr = 1; + $ftp->quit if $newerr; + if ( !$newerr ) { + $result = +"File: ediorder_$basketno.CEP transferred successfully"; + $ftp->quit; + unlink "${edi_files}ediorder_$basketno.CEP"; + LogEDITransaction( $ftpaccount->{id} ); + LogEDIFactOrder( $booksellerid, 'Sent', $basketno ); + return $result; + } + else { + $result = +"Could not transfer the file ${edi_files}ediorder_$basketno.CEP to $ftpaccount->{host}: $_"; + FTPError($result); + LogEDIFactOrder( $booksellerid, 'Failed', + $basketno ); + return $result; + } + } + else { + $result = +"Cannot get remote directory ($ftpaccount->{in_dir}) on $ftpaccount->{host}"; + FTPError($result); + LogEDIFactOrder( $booksellerid, 'Failed', $basketno ); + return $result; + } + } + else { + $result = "Cannot log in to $ftpaccount->{host}: $!"; + FTPError($result); + LogEDIFactOrder( $booksellerid, 'Failed', $basketno ); + return $result; + } + } + else { + $result = + "Cannot make an FTP connection to $ftpaccount->{host}: $!"; + FTPError($result); + LogEDIFactOrder( $booksellerid, 'Failed', $basketno ); + return $result; + } + } + else { + $result = +"Vendor ID: $booksellerid does not have a current EDIfact FTP account"; + FTPError($result); + LogEDIFactOrder( $booksellerid, 'Failed', $basketno ); + return $result; + } + } + else { + $result = "There is no EDIfact order for this basket"; + return $result; + } +} + +sub FTPError { + my $error = shift; + my $log_file = C4::Context->config('intranetdir'); + $log_file .= '/misc/edi_files/edi_ftp_error.log'; + open my $log_fh, '>>', $log_file + or croak "Could not open $log_file: $!"; + my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time); + printf $log_fh "%4d-%02d-%02d %02d:%02d:%02d\n-----\n", + $year + 1900, $mon + 1, $mday, $hour, $min, $sec; + print $log_fh "$error\n\n"; + close $log_fh; + return; +} + +=head2 SendQueuedEDIOrders + +Sends all EDIfact orders that are held in the Queued + +=cut + +sub SendQueuedEDIOrders { + my $dbh = C4::Context->dbh; + my @orders; + my $sth = $dbh->prepare( + q|select basketno, provider from edifact_messages where status='Queued'| + ); + $sth->execute(); + while ( @orders = $sth->fetchrow_array() ) { + SendEDIOrder( $orders[0], $orders[1] ); + } + return; +} + +=head2 ParseEDIQuote + +Uses Business::Edifact::Interchange to parse a stored EDIfact quote message, creates basket, biblios, biblioitems, and items + +=cut + +sub ParseEDIQuote { + my ( $filename, $booksellerid ) = @_; + my $ordernumber; + my $basketno; + my $ParseEDIQuoteItem; + + #print "file: $filename\n"; + my $edi = Business::Edifact::Interchange->new; + my $path = C4::Context->config('intranetdir'); + $path .= '/misc/edi_files/'; + $edi->parse_file("$path$filename"); + my $messages = $edi->messages(); + my $msg_cnt = @{$messages}; + + #print "messages: $msg_cnt\n"; + #print "type: ".$messages->[0]->type()."\n"; + #print "date: ".$messages->[0]->date_of_message()."\n"; + + # create default edifact_messages entry + my $messagekey = LogEDIFactQuote( $booksellerid, 'Failed', 0, 0 ); + + #create basket + if ( $msg_cnt > 0 && $booksellerid ) { + $basketno = NewBasket( $booksellerid, 0, $filename, '', '', '' ); + } + + $ParseEDIQuoteItem = sub { + my ( $item, $gir, $bookseller_id ) = @_; + my $relnos = $item->{related_numbers}; + my $author = $item->author_surname . ", " . $item->author_firstname; + + my $ecost = + GetDiscountedPrice( $bookseller_id, $item->{price}->{price} ); + + my $ftxlin; + my $ftxlno; + if ( $item->{free_text}->{qualifier} eq "LIN" ) { + $ftxlin = $item->{free_text}->{text}; + } + if ( $item->{free_text}->{qualifier} eq "LNO" ) { + $ftxlno = $item->{free_text}->{text}; + } + + my ( $llo, $lfn, $lsq, $lst, $lfs, $lcl, $id ); + my $relcount = 0; + foreach my $rel ( @{$relnos} ) { + if ( $rel->{id} == ( $gir + 1 ) ) { + if ( $item->{related_numbers}->[$relcount]->{LLO}->[0] ) { + $llo = $item->{related_numbers}->[$relcount]->{LLO}->[0]; + } + if ( $item->{related_numbers}->[$relcount]->{LFN}->[0] ) { + $lfn = $item->{related_numbers}->[$relcount]->{LFN}->[0]; + } + if ( $item->{related_numbers}->[$relcount]->{LSQ}->[0] ) { + $lsq = $item->{related_numbers}->[$relcount]->{LSQ}->[0]; + } + if ( $item->{related_numbers}->[$relcount]->{LST}->[0] ) { + $lst = $item->{related_numbers}->[$relcount]->{LST}->[0]; + } + if ( $item->{related_numbers}->[$relcount]->{LFS}->[0] ) { + $lfs = $item->{related_numbers}->[$relcount]->{LFS}->[0]; + } + if ( $item->{related_numbers}->[$relcount]->{LCL}->[0] ) { + $lcl = $item->{related_numbers}->[$relcount]->{LCL}->[0]; + } + if ( $item->{related_numbers}->[$relcount]->{id} ) { + $id = $item->{related_numbers}->[$relcount]->{id}; + } + } + $relcount++; + } + + my $lclnote; + if ( !$lst ) { + $lst = uc( $item->item_format ); + } + if ( !$lcl ) { + $lcl = $item->shelfmark; + } + else { + ( $lcl, $lclnote ) = DawsonsLCL($lcl); + } + if ($lfs) { + $lcl .= " $lfs"; + } + + my $budget_id = GetBudgetID($lfn); + + #Uncomment section below to define a default budget_id if there is no match + #if (!defined $budget_id) + #{ + # $budget_id=0; + #} + + # create biblio record + my $bib_record = TransformKohaToMarc( + { + 'biblio.title' => $item->title, + 'biblio.author' => $author ? $author : q{}, + 'biblio.seriestitle' => q{}, + 'biblioitems.isbn' => $item->{item_number} + ? $item->{item_number} + : q{}, + 'biblioitems.publishercode' => $item->publisher + ? $item->publisher + : q{}, + 'biblioitems.publicationyear' => $item->date_of_publication + ? $item->date_of_publication + : q{}, + 'biblio.copyrightdate' => $item->date_of_publication + ? $item->date_of_publication + : q{}, + 'biblioitems.itemtype' => uc( $item->item_format ), + 'biblioitems.cn_source' => 'ddc', + 'items.cn_source' => 'ddc', + 'items.notforloan' => -1, + + #"items.ccode" => $lsq, + 'items.location' => $lsq, + 'items.homebranch' => $llo, + 'items.holdingbranch' => $llo, + 'items.booksellerid' => $bookseller_id, + 'items.price' => $item->{price}->{price}, + 'items.replacementprice' => $item->{price}->{price}, + 'items.itemcallnumber' => $lcl, + 'items.itype' => $lst, + 'items.cn_sort' => q{}, + } + ); + + #check if item already exists in catalogue + my $biblionumber; + my $bibitemnumber; + ( $biblionumber, $bibitemnumber ) = + CheckOrderItemExists( $item->{item_number} ); + + if ( !defined $biblionumber ) { + + # create the record in catalogue, with framework '' + ( $biblionumber, $bibitemnumber ) = AddBiblio( $bib_record, q{} ); + } + + my $ordernote; + if ($lclnote) { + $ordernote = $lclnote; + } + if ($ftxlno) { + $ordernote = $ftxlno; + } + if ($ftxlin) { + $ordernote = $ftxlin; + } + + my %orderinfo = ( + basketno => $basketno, + ordernumber => q{}, + subscription => 'no', + uncertainprice => 0, + biblionumber => $biblionumber, + title => $item->title, + quantity => 1, + biblioitemnumber => $bibitemnumber, + rrp => $item->{price}->{price}, + ecost => $ecost, + sort1 => q{}, + sort2 => q{}, + booksellerinvoicenumber => $item->{item_reference}[0][1], + listprice => $item->{price}->{price}, + branchcode => $llo, + budget_id => $budget_id, + notes => $ordernote, + ); + + my $orderinfo = \%orderinfo; + + my ( $retbasketno, $ordernumber ) = NewOrder($orderinfo); + + # now, add items if applicable + if ( C4::Context->preference('AcqCreateItem') eq 'ordering' ) { + my $itemnumber; + ( $biblionumber, $bibitemnumber, $itemnumber ) = + AddItemFromMarc( $bib_record, $biblionumber ); + NewOrderItem( $itemnumber, $ordernumber ); + } + }; + + for ( my $count = 0 ; $count < $msg_cnt ; $count++ ) { + my $items = $messages->[$count]->items(); + my $ref_num = $messages->[$count]->{ref_num}; + + foreach my $item ( @{$items} ) { + for ( my $i = 0 ; $i < $item->{quantity} ; $i++ ) { + &$ParseEDIQuoteItem( $item, $i, $booksellerid, $basketno ); + } + } + } + + # update edifact_messages entry + $messagekey = + LogEDIFactQuote( $booksellerid, 'Received', $basketno, $messagekey ); + return 1; + +} + +=head2 GetDiscountedPrice + +Returns the discounted price for an order based on the discount rate for a given vendor + +=cut + +sub GetDiscountedPrice { + my ( $booksellerid, $price ) = @_; + my $dbh = C4::Context->dbh; + my $sth; + my @discount; + my $ecost; + my $percentage; + $sth = $dbh->prepare(q|select discount from aqbooksellers where id=?|); + $sth->execute($booksellerid); + + while ( @discount = $sth->fetchrow_array() ) { + $percentage = $discount[0]; + } + $ecost = ( $price - ( ( $percentage * $price ) / 100 ) ); + return $ecost; +} + +=head2 DawsonsLCL + +Checks for a call number encased by asterisks. If found, returns call number as $lcl and string with +asterisks as $lclnote to go into FTX field enabling spine label creation by Dawsons bookseller + +=cut + +sub DawsonsLCL { + my $lcl = shift; + my $lclnote; + my $f = index( $lcl, '*' ); + my $l = rindex( $lcl, '*' ); + if ( $f == 0 && $l == ( length($lcl) - 1 ) ) { + $lclnote = $lcl; + $lcl =~ s/\*//g; + } + return ( $lcl, $lclnote ); +} + +=head2 GetBudgetID + +Returns the budget_id for a given budget_code + +=cut + +sub GetBudgetID { + my $fundcode = shift; + my $dbh = C4::Context->dbh; + my $sth; + my @funds; + my $ecost; + my $budget_id; + $sth = $dbh->prepare("select budget_id from aqbudgets where budget_code=?"); + $sth->execute($fundcode); + + while ( @funds = $sth->fetchrow_array() ) { + $budget_id = $funds[0]; + } + return $budget_id; +} + +=head2 CheckOrderItemExists + +Checks to see if a biblio record already exists in the catalogue when parsing a quotes message +Converts 10-13 digit ISBNs and vice-versa if an initial match is not found + +=cut + +sub CheckOrderItemExists { + my $isbn = shift; + my $dbh = C4::Context->dbh; + my $sth; + my @matches; + my $biblionumber; + my $bibitemnumber; + $sth = $dbh->prepare( + "select biblionumber, biblioitemnumber from biblioitems where isbn=?"); + $sth->execute($isbn); + + while ( @matches = $sth->fetchrow_array() ) { + $biblionumber = $matches[0]; + $bibitemnumber = $matches[1]; + } + if ($biblionumber) { + return $biblionumber, $bibitemnumber; + } + else { + $isbn = cleanisbn($isbn); + if ( length($isbn) == 10 ) { + $isbn = Business::ISBN->new($isbn); + if ($isbn) { + if ( $isbn->is_valid ) { + $isbn = ( $isbn->as_isbn13 )->isbn; + $sth->execute($isbn); + while ( @matches = $sth->fetchrow_array() ) { + $biblionumber = $matches[0]; + $bibitemnumber = $matches[1]; + } + } + } + } + elsif ( length($isbn) == 13 ) { + $isbn = Business::ISBN->new($isbn); + if ($isbn) { + if ( $isbn->is_valid ) { + $isbn = ( $isbn->as_isbn10 )->isbn; + $sth->execute($isbn); + while ( @matches = $sth->fetchrow_array() ) { + $biblionumber = $matches[0]; + $bibitemnumber = $matches[1]; + } + } + } + } + return $biblionumber, $bibitemnumber; + } +} + +sub string35escape { + my $string = shift; + my $colon_string; + my @sections; + if ( length($string) > 35 ) { + my ( $chunk, $stringlength ) = ( 35, length($string) ); + for ( my $counter = 0 ; $counter < $stringlength ; $counter += $chunk ) + { + push @sections, substr( $string, $counter, $chunk ); + } + foreach my $section (@sections) { + $colon_string .= $section . ":"; + } + chop $colon_string; + } + else { + $colon_string = $string; + } + return $colon_string; +} + +sub GetOrderItemInfo { + my $ordernumber = shift; + my $dbh = C4::Context->dbh; + my $sth; + my @rows; + my $homebranch; + my $callnumber; + my $itype; + my $ccode; + my $fund; + $sth = $dbh->prepare( +q|select items.homebranch, items.itemcallnumber, items.itype, items.location from items + inner join aqorders_items on aqorders_items.itemnumber=items.itemnumber + where aqorders_items.ordernumber=?| + ); + $sth->execute($ordernumber); + + while ( @rows = $sth->fetchrow_array() ) { + $homebranch = $rows[0]; + $callnumber = $rows[1]; + $itype = $rows[2]; + $ccode = $rows[3]; + } + $sth = $dbh->prepare( + q|select aqbudgets.budget_code from aqbudgets inner join aqorders on + aqorders.budget_id=aqbudgets.budget_id where aqorders.ordernumber=?| + ); + $sth->execute($ordernumber); + while ( @rows = $sth->fetchrow_array() ) { + $fund = $rows[0]; + } + return $homebranch, $callnumber, $itype, $ccode, $fund; +} + +sub CheckVendorFTPAccountExists { + my $booksellerid = shift; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( + q|select count(id) from vendor_edi_accounts where provider=?|); + $sth->execute($booksellerid); + while ( my @rows = $sth->fetchrow_array() ) { + if ( $rows[0] > 0 ) { + return 1; + } + } + return; +} + +1; + +__END__ + +=head1 AUTHOR + +Mark Gavillet + +=cut diff --git a/acqui/basket.pl b/acqui/basket.pl index 9b36c14..3218d98 100755 --- a/acqui/basket.pl +++ b/acqui/basket.pl @@ -28,6 +28,7 @@ use C4::Output; use CGI; use C4::Acquisition; use C4::Budgets; +use C4::EDI; use C4::Bookseller qw( GetBookSellerFromId); use C4::Debug; use C4::Biblio; @@ -86,6 +87,8 @@ my $basket = GetBasket($basketno); # if no booksellerid in parameter, get it from basket # warn "=>".$basket->{booksellerid}; $booksellerid = $basket->{booksellerid} unless $booksellerid; +my $ediaccount = CheckVendorFTPAccountExists($booksellerid); +$template->param(ediaccount=>$ediaccount); my ($bookseller) = GetBookSellerFromId($booksellerid); my $op = $query->param('op'); if (!defined $op) { @@ -95,6 +98,15 @@ if (!defined $op) { my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1'; $template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2'; +if ( $op eq 'ediorder') { + my $edifile=CreateEDIOrder($basketno,$booksellerid); + $template->param(edifile => $edifile); +} +if ( $op eq 'edisend') { + my $edisend=SendEDIOrder($basketno,$booksellerid); + $template->param(edisend => $edisend); +} + if ( $op eq 'delete_confirm' ) { my $basketno = $query->param('basketno'); DelBasket($basketno); diff --git a/admin/edi-accounts.pl b/admin/edi-accounts.pl new file mode 100755 index 0000000..86f3a3e --- /dev/null +++ b/admin/edi-accounts.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl + +# Copyright 2011,2012 Mark Gavillet & PTFS Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Auth; +use C4::Output; +use C4::EDI; + +my $input = CGI->new(); + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "admin/edi-accounts.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => { borrowers => 1 }, + } +); + +my $op = $input->param('op'); +$template->param( op => $op ); + +if ( $op eq "delsubmit" ) { + my $del = C4::EDI::DeleteEDIDetails( $input->param('id') ); + $template->param( opdelsubmit => 1 ); +} + +if ( $op eq "addsubmit" ) { + CreateEDIDetails( + $input->param('provider'), $input->param('description'), + $input->param('host'), $input->param('user'), + $input->param('pass'), $input->param('path'), + $input->param('in_dir'), $input->param('san') + ); + $template->param( opaddsubmit => 1 ); +} + +if ( $op eq "editsubmit" ) { + UpdateEDIDetails( + $input->param('editid'), $input->param('description'), + $input->param('host'), $input->param('user'), + $input->param('pass'), $input->param('provider'), + $input->param('path'), $input->param('in_dir'), + $input->param('san') + ); + $template->param( opeditsubmit => 1 ); +} + +my $ediaccounts = C4::EDI::GetEDIAccounts; +$template->param( ediaccounts => $ediaccounts ); + +output_html_with_http_headers $input, $cookie, $template->output; diff --git a/admin/edi-edit.pl b/admin/edi-edit.pl new file mode 100755 index 0000000..fa98c8d --- /dev/null +++ b/admin/edi-edit.pl @@ -0,0 +1,73 @@ +#!/usr/bin/perl + +# Copyright 2011 Mark Gavillet & PTFS Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Auth; +use C4::Output; +use C4::EDI; + +my $input = CGI->new(); + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "admin/edi-edit.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => { borrowers => 1 }, + } +); +my $vendorlist = C4::EDI::GetVendorList; + +my $op = $input->param('op'); +$template->param( op => $op ); + +if ( $op eq "add" ) { + $template->param( opaddsubmit => "addsubmit" ); +} +if ( $op eq "edit" ) { + $template->param( opeditsubmit => "editsubmit" ); + my $edi_details = C4::EDI::GetEDIAccountDetails( $input->param('id') ); + my $selectedprovider = $edi_details->{'provider'}; + foreach my $prov (@$vendorlist) { + $prov->{selected} = 'selected' + if $prov->{'id'} == $selectedprovider; + } + $template->param( + editid => $edi_details->{'id'}, + description => $edi_details->{'description'}, + host => $edi_details->{'host'}, + user => $edi_details->{'username'}, + pass => $edi_details->{'password'}, + provider => $edi_details->{'provider'}, + in_dir => $edi_details->{'in_dir'}, + san => $edi_details->{'san'} + ); +} +if ( $op eq "del" ) { + $template->param( opdelsubmit => "delsubmit" ); + $template->param( opdel => 1 ); + $template->param( id => $input->param('id') ); +} + +$template->param( vendorlist => $vendorlist ); + +output_html_with_http_headers $input, $cookie, $template->output; diff --git a/installer/data/mysql/atomicupdate/edifact.sql b/installer/data/mysql/atomicupdate/edifact.sql new file mode 100644 index 0000000..628f6bf --- /dev/null +++ b/installer/data/mysql/atomicupdate/edifact.sql @@ -0,0 +1,27 @@ +CREATE TABLE IF NOT EXISTS `vendor_edi_accounts` ( + `id` int(11) NOT NULL auto_increment, + `description` text NOT NULL, + `host` text, + `username` text, + `password` text, + `last_activity` date default NULL, + `provider` int(11) default NULL, + `in_dir` text, + `san` varchar(10) default NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `edifact_messages` ( + `key` int(11) NOT NULL auto_increment, + `message_type` text NOT NULL, + `date_sent` date default NULL, + `provider` int(11) default NULL, + `status` text, + `basketno` int(11) NOT NULL default '0', + PRIMARY KEY (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +insert into permissions (module_bit, code, description) values (13, 'edi_manage', 'Manage EDIFACT transmissions'); + +INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES +('EDIfactEAN', '56781234', '', 'EAN identifier for the library used in EDIfact messages', 'Textarea'); \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc index 72162d3..f961510 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc @@ -61,7 +61,8 @@ diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc index c209de4..9fb2cc4 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc @@ -23,7 +23,7 @@ [% IF ( CAN_user_tools_import_patrons ) %]
  • Import patrons
  • [% END %] - [% IF ( CAN_user_tools_edit_notices ) %] + [% IF CAN_user_tools_edit_notices %]
  • Notices & slips
  • [% END %] [% IF ( CAN_user_tools_edit_notice_status_triggers ) %] @@ -98,4 +98,7 @@ [% IF ( CAN_user_tools_edit_quotes ) %]
  • Quote editor
  • [% END %] + [% IF ( CAN_user_tools_edi_manage ) %] +
  • EDIfact messages
  • + [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt index dcd6ccb..347e6eb 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt @@ -120,6 +120,7 @@ new YAHOO.widget.Button("basketheadbutton"); new YAHOO.widget.Button("exportbutton"); new YAHOO.widget.Button("delbasketbutton"); + new YAHOO.widget.Button("ediorderbutton"); } //]]> @@ -134,6 +135,9 @@
  • Close this basket
  • [% END %]
  • Export this basket as CSV
  • + [% IF ediaccount %] +
  • EDIfact order
  • + [% END %] @@ -159,7 +163,12 @@ [% END %] [% END %] [% END %] - + [% IF ( edifile ) %] +
    EDIfact order created and will be sent overnight. Filename: [% edifile %] - Send this order now?
    + [% END %] + [% IF ( edisend ) %] +
    [% edisend %]
    + [% END %] [% IF ( NO_BOOKSELLER ) %]

    Vendor not found

    [% ELSE %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt index 88fabe9..aa21ed9 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt @@ -107,6 +107,8 @@
    Printers (UNIX paths).
    -->
    Z39.50 client targets
    Define which servers to query for MARC data in the integrated Z39.50 client.
    +
    EDI Accounts
    +
    Manage vendor EDI accounts for import/export
    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-accounts.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-accounts.tt new file mode 100644 index 0000000..fae2c8c --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-accounts.tt @@ -0,0 +1,46 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Administration - EDI Accounts +[% INCLUDE 'doc-head-close.inc' %] + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
    +
    +
    +
    Vendor EDI Accounts + [% IF ( ediaccounts ) %] +
    + [% IF ( opdelsubmit ) %] +
    The account was successfully deleted
    + [% END %] + [% IF ( opaddsubmit ) %] +
    The account was successfully added
    + [% END %] + [% IF ( opeditsubmit ) %] +
    The account was successfully updated
    + [% END %] + + + + [% FOREACH account IN ediaccounts %] + + [% END %] +
    IDVendorDescriptionLast activityActions
    [% account.id %][% account.vendor %][% account.description %][% account.last_activity %]Edit | Delete
    +
    + [% ELSE %] +

    You currently do not have any Vendor EDI Accounts. To add a new account click here.

    + [% END %] +
    +
    +
    + [% INCLUDE 'admin-menu.inc' %] +
    +
    +
    +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-edit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-edit.tt new file mode 100644 index 0000000..dedbaf9 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-edit.tt @@ -0,0 +1,102 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Administration - EDI Accounts +[% INCLUDE 'doc-head-close.inc' %] + +[% INCLUDE 'calendar.inc' %] + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + +
    +
    +
    +
    +

    Vendor EDI Accounts

    +
    You must complete all required fields
    +
    + + + + [% IF opdel %] +

    Are you sure you want to delete this account?

    +

    YES | NO

    + [% ELSE %] +
    + EDI Account details +
      +
    1. + + +
    2. +
    3. + + +
    4. +
    5. + + +
    6. +
    7. + + +
    8. +
    9. + + +
    10. +
    11. + + +
    12. +
    13. + + +
    14. +
    +
    +
    + + Cancel +
    + [% END %] +
    + +
    +
    +
    + [% INCLUDE 'admin-menu.inc' %] +
    +
    +
    +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/edi.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/edi.tt new file mode 100644 index 0000000..da92ac2 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/edi.tt @@ -0,0 +1,54 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Tools › EDIfact messages +[% INCLUDE 'doc-head-close.inc' %] + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
    +
    +
    +
    EDIfact messages + [% IF messagelist %] +
    + [% IF opdelsubmit %] +
    The account was successfully deleted
    + [% END %] + [% IF opaddsubmit %] +
    The account was successfully added
    + [% END %] + [% IF opeditsubmit %] +
    The account was successfully updated
    + [% END %] + + + [% FOREACH message IN messagelist %] + + [% END %] +
    DateMessage typeProviderStatusBasket
    [% message.date_sent %][% message.message_type %][% message.providername %][% message.status %][% IF ( message.basketno ) %]View basket[% END %]
    +
    + + [% ELSE %] +

    There are currently no EDIfact messages to display.

    + [% END %] +
    +
    +
    + [% INCLUDE 'tools-menu.inc' %] +
    +
    +
    +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt index 52cc1e6..ad35056 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt @@ -97,6 +97,11 @@
    Quote editor for Quote-of-the-day feature in OPAC
    [% END %] + [% IF ( CAN_user_tools_edi_manage ) %] +
    EDIfact messages
    +
    Manage EDIfact transmissions
    + [% END %] +
    diff --git a/misc/cronjobs/clean_edifiles.pl b/misc/cronjobs/clean_edifiles.pl new file mode 100755 index 0000000..ac33516 --- /dev/null +++ b/misc/cronjobs/clean_edifiles.pl @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +# Copyright 2011 Mark Gavillet & PTFS Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Context; +my $edidir = C4::Context->config('intranetdir'); + +$edidir .= '/misc/edi_files'; +opendir( my $dh, $edidir ); +my @files = readdir($dh); +close $dh; + +foreach my $file (@files) { + my $now = time; + my @stat = stat("$edidir/$file"); + if ( + $stat[9] < ( $now - 2592000 ) + && ( ( index lc($file), '.ceq' ) > -1 + || ( index lc($file), '.cep' ) > -1 ) + ) + { + print "Deleting file $edidir/$file..."; + unlink("$edidir/$file"); + print "Done.\n"; + } +} diff --git a/misc/cronjobs/edifact_order_ftp_transfer.pl b/misc/cronjobs/edifact_order_ftp_transfer.pl new file mode 100755 index 0000000..f01c2ae --- /dev/null +++ b/misc/cronjobs/edifact_order_ftp_transfer.pl @@ -0,0 +1,132 @@ +#!/usr/bin/perl + +# Copyright 2011,2012 Mark Gavillet & PTFS Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Context; +use C4::Auth; +use C4::Output; +use C4::EDI; +use Net::FTP; + +my $ftpaccounts = C4::EDI::GetEDIFTPAccounts; + +my @ERRORS; +my @putdirlist; +my $newerr; +my @files; +my $putdir = C4::Context->config('intranetdir'); +$putdir .= '/misc/edi_files/'; +my $ediparse; +opendir( my $dh, $putdir ); +@putdirlist = readdir $dh; +closedir $dh; + +foreach my $accounts (@$ftpaccounts) { + my $ftp = Net::FTP->new( $accounts->{host}, Timeout => 10, Passive => 1 ) + or $newerr = 1; + $ftp->binary(); + push @ERRORS, "Can't ftp to $accounts->{host}: $!\n" if $newerr; + myerr() if $newerr; + if ( !$newerr ) { + $newerr = 0; + print "Connected to $accounts->{host}\n"; + + $ftp->login( "$accounts->{username}", "$accounts->{password}" ) + or $newerr = 1; + print "Getting file list\n"; + push @ERRORS, "Can't login to $accounts->{host}: $!\n" if $newerr; + $ftp->quit if $newerr; + myerr() if $newerr; + if ( !$newerr ) { + print "Logged in\n"; + $ftp->cwd( $accounts->{in_dir} ) or $newerr = 1; + push @ERRORS, "Can't cd in server $accounts->{host} $!\n" + if $newerr; + myerr() if $newerr; + $ftp->quit if $newerr; + + @files = $ftp->ls or $newerr = 1; + push @ERRORS, + "Can't get file list from server $accounts->{host} $!\n" + if $newerr; + myerr() if $newerr; + if ( !$newerr ) { + print "Got file list\n"; + foreach my $file (@files) { + if ( ( index lc($_), '.ceq' ) > -1 ) { + my $match; + foreach my $f (@putdirlist) { + if ( $f eq $file ) { + $match = 1; + last; + } + } + if ( $match != 1 ) { + chdir $putdir; + $ftp->get($_) or $newerr = 1; + push @ERRORS, +"Can't transfer file ($_) from $accounts->{host} $!\n" + if $newerr; + $ftp->quit if $newerr; + myerr() if $newerr; + if ( !$newerr ) { + $ediparse = + ParseEDIQuote( $_, $accounts->{provider} ); + } + if ( $ediparse == 1 ) { + my $qext = '.ceq'; + my $rext = '.eeq'; + my $renamed = lc($_); + $renamed =~ s/$qext/$rext/g; + $ftp->rename( $_, $renamed ); + } + } + } + } + } + } + if ( !$newerr ) { + LogEDITransaction("$accounts->{id}"); + } + $ftp->quit; + } + $newerr = 0; +} + +print "\n@ERRORS\n"; + +if (@ERRORS) { + my $logfile = C4::Context->config('intranetdir'); + $logfile .= '/misc/edi_files/edi_ftp_error.log'; + open my $fh, '>>', $logfile; + my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time); + printf $fh "%4d-%02d-%02d %02d:%02d:%02d\n-----\n", $year + 1900, + $mon + 1, $mday, $hour, $min, $sec; + print $fh "@ERRORS\n"; + close $fh; +} + +sub myerr { + print 'Error: '; + print @ERRORS; + return; +} + diff --git a/misc/cronjobs/send_queued_edi_orders.pl b/misc/cronjobs/send_queued_edi_orders.pl new file mode 100755 index 0000000..8eeedcc --- /dev/null +++ b/misc/cronjobs/send_queued_edi_orders.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl + +# Copyright 2011 Mark Gavillet & PTFS Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Auth; +use C4::Output; +use C4::EDI; + + +SendQueuedEDIOrders(); \ No newline at end of file diff --git a/tools/edi.pl b/tools/edi.pl new file mode 100755 index 0000000..ba5d563 --- /dev/null +++ b/tools/edi.pl @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +# Copyright 2011 Mark Gavillet & PTFS Europe Ltd +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use CGI; +use C4::Auth; +use C4::Output; +use C4::EDI; + +my $input = CGI->new(); + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "tools/edi.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => { borrowers => 1 }, + } +); + +my $messagelist = C4::EDI::GetEDIfactMessageList(); + +$template->param( messagelist => $messagelist ); + +output_html_with_http_headers $input, $cookie, $template->output; -- 1.7.12.1.382.gb0576a6