View | Details | Raw Unified | Return to bug 7736
Collapse All | Expand All

(-)a/C4/EDI.pm (+1086 lines)
Line 0 Link Here
1
package C4::EDI;
2
3
# Copyright 2011 Mark Gavillet
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use C4::Context;
23
use C4::Acquisition;
24
use C4::Budgets qw( GetCurrency );
25
use Net::FTP;
26
use Business::Edifact::Interchange;
27
use C4::Biblio;
28
use C4::Items;
29
use Business::ISBN;
30
use Carp;
31
use parent qw(Exporter);
32
33
our $VERSION   = 3.09.00.53;
34
our @EXPORT_OK = qw(
35
  GetEDIAccounts
36
  GetEDIAccountDetails
37
  CreateEDIDetails
38
  UpdateEDIDetails
39
  LogEDIFactOrder
40
  LogEDIFactQuote
41
  DeleteEDIDetails
42
  GetVendorList
43
  GetEDIfactMessageList
44
  GetEDIFTPAccounts
45
  LogEDITransaction
46
  GetVendorSAN
47
  CreateEDIOrder
48
  SendEDIOrder
49
  SendQueuedEDIOrders
50
  ParseEDIQuote
51
  GetDiscountedPrice
52
  GetBudgetID
53
  CheckOrderItemExists
54
  GetBranchCode
55
  string35escape
56
  GetOrderItemInfo
57
  CheckVendorFTPAccountExists
58
);
59
60
=head1 NAME
61
62
C4::EDI - Perl Module containing functions for Vendor EDI accounts and EDIfact messages
63
64
=head1 VERSION
65
66
Version 0.01
67
68
=head1 SYNOPSIS
69
70
use C4::EDI;
71
72
=head1 DESCRIPTION
73
74
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
75
76
=head2 GetVendorList
77
78
Returns a list of vendors from aqbooksellers to populate drop down select menu
79
80
=cut
81
82
sub GetVendorList {
83
    my $dbh = C4::Context->dbh;
84
    my $sth;
85
    $sth =
86
      $dbh->prepare('select id, name from aqbooksellers order by name asc');
87
    $sth->execute();
88
    my $vendorlist = $sth->fetchall_arrayref( {} );
89
    return $vendorlist;
90
}
91
92
=head2 CreateEDIDetails
93
94
Inserts a new EDI vendor FTP account
95
96
=cut
97
98
sub CreateEDIDetails {
99
    my ( $provider, $description, $host, $user, $pass, $in_dir, $san ) = @_;
100
    my $dbh = C4::Context->dbh;
101
    my $sth;
102
    if ($provider) {
103
        $sth = $dbh->prepare(
104
'insert into vendor_edi_accounts (description, host, username, password, provider, in_dir, san) values (?,?,?,?,?,?,?)'
105
        );
106
        $sth->execute( $description, $host, $user,
107
            $pass, $provider, $in_dir, $san );
108
    }
109
    return;
110
}
111
112
=head2 GetEDIAccounts
113
114
Returns all vendor FTP accounts
115
116
=cut
117
118
sub GetEDIAccounts {
119
    my $dbh = C4::Context->dbh;
120
    my $sth;
121
    $sth = $dbh->prepare(
122
'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'
123
    );
124
    $sth->execute();
125
    my $ediaccounts = $sth->fetchall_arrayref( {} );
126
    return $ediaccounts;
127
}
128
129
=head2 DeleteEDIDetails
130
131
Remove a vendor's FTP account
132
133
=cut
134
135
sub DeleteEDIDetails {
136
    my ($id) = @_;
137
    my $dbh = C4::Context->dbh;
138
    my $sth;
139
    if ($id) {
140
        $sth = $dbh->prepare('delete from vendor_edi_accounts where id=?');
141
        $sth->execute($id);
142
    }
143
    return;
144
}
145
146
=head2 UpdateEDIDetails
147
148
Update a vendor's FTP account
149
150
=cut
151
152
sub UpdateEDIDetails {
153
    my ( $editid, $description, $host, $user, $pass, $provider, $in_dir, $san )
154
      = @_;
155
    my $dbh = C4::Context->dbh;
156
    if ($editid) {
157
        my $sth = $dbh->prepare(
158
'update vendor_edi_accounts set description=?, host=?, username=?, password=?, provider=?, in_dir=?, san=? where id=?'
159
        );
160
        $sth->execute( $description, $host, $user, $pass, $provider, $in_dir,
161
            $san, $editid );
162
    }
163
    return;
164
}
165
166
=head2 LogEDIFactOrder
167
168
Updates or inserts to the edifact_messages table when processing an order and assigns a status and basket number
169
170
=cut
171
172
sub LogEDIFactOrder {
173
    my ( $provider, $status, $basketno ) = @_;
174
    my $dbh = C4::Context->dbh;
175
    my $key;
176
    my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
177
    my $date_sent = sprintf '%4d-%02d-%0d', $year + 1900, $mon + 1, $mday;
178
    my $sth = $dbh->prepare(
179
'select edifact_messages.id from edifact_messages where basketno=? and provider=?'
180
    );
181
    $sth->execute( $basketno, $provider );
182
183
    while ( my @row = $sth->fetchrow_array() ) {
184
        $key = $row[0];
185
    }
186
    if ($key) {
187
        $sth = $dbh->prepare(
188
'update edifact_messages set date_sent=?, status=? where edifact_messages.id=?'
189
        );
190
        $sth->execute( $date_sent, $status, $key );
191
    }
192
    else {
193
        $sth = $dbh->prepare(
194
'insert into edifact_messages (message_type,date_sent,provider,status,basketno) values (?,?,?,?,?)'
195
        );
196
        $sth->execute( 'ORDER', $date_sent, $provider, $status, $basketno );
197
    }
198
    return;
199
}
200
201
=head2 LogEDIFactOrder
202
203
Updates or inserts to the edifact_messages table when processing a quote and assigns a status and basket number
204
205
=cut
206
207
sub LogEDIFactQuote {
208
    my ( $provider, $status, $basketno, $key ) = @_;
209
    my $dbh = C4::Context->dbh;
210
    my $sth;
211
    my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
212
    my $date_sent = sprintf '%4d-%02d-%0d', $year + 1900, $mon + 1, $mday;
213
    if ( $key != 0 ) {
214
        $sth = $dbh->prepare(
215
'update edifact_messages set date_sent=?, status=?, basketno=? where edifact_messages.id=?'
216
        );
217
        $sth->execute( $date_sent, $status, $basketno, $key );
218
    }
219
    else {
220
        $sth = $dbh->prepare(
221
'insert into edifact_messages (message_type,date_sent,provider,status,basketno) values (?,?,?,?,?)'
222
        );
223
        $sth->execute( 'QUOTE', $date_sent, $provider, $status, $basketno );
224
        $key =
225
          $dbh->last_insert_id( undef, undef, qw(edifact_messages id), undef );
226
    }
227
    return $key;
228
}
229
230
=head2 GetEDIAccountDetails
231
232
Returns FTP account details for a given vendor
233
234
=cut
235
236
sub GetEDIAccountDetails {
237
    my ($id) = @_;
238
    my $dbh = C4::Context->dbh;
239
    my $sth;
240
    if ($id) {
241
        $sth = $dbh->prepare('select * from vendor_edi_accounts where id=?');
242
        $sth->execute($id);
243
        return $sth->fetchrow_hashref;
244
    }
245
    return;
246
}
247
248
=head2 GetEDIfactMessageList
249
250
Returns a list of edifact_messages that have been processed, including the type (quote/order) and status
251
252
=cut
253
254
sub GetEDIfactMessageList {
255
    my $dbh = C4::Context->dbh;
256
    my $sth;
257
    $sth = $dbh->prepare(
258
q|select edifact_messages.id, 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.id desc|
259
    );
260
    $sth->execute();
261
    return $sth->fetchall_arrayref( {} );
262
}
263
264
=head2 GetEDIFTPAccounts
265
266
Returns all vendor FTP accounts. Used when retrieving quotes messages overnight
267
268
=cut
269
270
sub GetEDIFTPAccounts {
271
    my $dbh = C4::Context->dbh;
272
    my $sth = $dbh->prepare(
273
'select id, host, username, password, provider, in_dir from vendor_edi_accounts order by id asc'
274
    );
275
    $sth->execute();
276
    return $sth->fetchall_arrayref( {} );
277
}
278
279
=head2 LogEDITransaction
280
281
Updates the timestamp for a given vendor FTP account whenever there is activity
282
283
=cut
284
285
sub LogEDITransaction {
286
    my $id = shift;
287
    my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
288
    my $datestamp = sprintf '%4d/%02d/%0d', $year + 1900, $mon + 1, $mday;
289
    my $dbh       = C4::Context->dbh;
290
    my $sth       = $dbh->prepare(
291
        'update vendor_edi_accounts set last_activity=? where id=?');
292
    $sth->execute( $datestamp, $id );
293
    return;
294
}
295
296
=head2 GetVendorSAN
297
298
Returns the stored SAN number for a given vendor
299
300
=cut
301
302
sub GetVendorSAN {
303
    my $booksellerid = shift;
304
    my $dbh          = C4::Context->dbh;
305
    my $san;
306
    my $sth =
307
      $dbh->prepare('select san from vendor_edi_accounts where provider=?');
308
    $sth->execute($booksellerid);
309
    while ( my @result = $sth->fetchrow_array() ) {
310
        $san = $result[0];
311
    }
312
    return $san;
313
}
314
315
=head2 CreateEDIOrder
316
317
Formats an EDIfact order message from a given basket and stores as a file on the server
318
319
=cut
320
321
sub CreateEDIOrder {
322
    my ( $basketno, $booksellerid ) = @_;
323
    my @datetime     = localtime(time);
324
    my $longyear     = $datetime[5] + 1900;
325
    my $shortyear    = sprintf '%02d', $datetime[5] - 100;
326
    my $date         = sprintf '%02d%02d', $datetime[4] + 1, $datetime[3];
327
    my $hourmin      = sprintf '%02d%02d', $datetime[2], $datetime[1];
328
    my $year         = $datetime[5] - 100;
329
    my $month        = sprintf '%02d', $datetime[4] + 1;
330
    my $linecount    = 0;
331
    my $filename     = "ediorder_$basketno.CEP";
332
    my $exchange     = int( rand(99999999999999) );
333
    my $ref          = int( rand(99999999999999) );
334
    my $san          = GetVendorSAN($booksellerid);
335
    my $message_type = GetMessageType($basketno);
336
    my $output_file  = C4::Context->config('intranetdir');
337
338
    # Currencies must be the 3 upper case alpha codes
339
    # Koha soes not currently enforce this
340
    my $default_currency = GetCurrency();
341
    if ( $default_currency->{currency} =~ m/^[[:upper:]]{3}$/ ) {
342
        $default_currency = $default_currency->{currency};
343
    }
344
    else {
345
        $default_currency = 'GBP';
346
    }
347
348
    $output_file .= "/misc/edi_files/$filename";
349
350
    open my $fh, '>', $output_file
351
      or croak "Unable to create $output_file : $!";
352
353
    print $fh q{UNA:+.? '};    # print opening header
354
    print $fh q{UNB+UNOC:2+}
355
      . C4::Context->preference("EDIfactEAN")
356
      . ":14+$san:31B+$shortyear$date:$hourmin+"
357
      . $exchange
358
      . "++ORDERS+++EANCOM'"
359
      ;    # print identifying EANs/SANs, date/time, exchange reference number
360
    print $fh 'UNH+' . $ref
361
      . q{+ORDERS:D:96A:UN:EAN008'};    # print message reference number
362
363
    if ( $message_type eq 'QUOTE' ) {
364
        print $fh 'BGM+22V+'
365
          . $basketno
366
          . q{+9'};    # print order number and quote confirmation ref
367
    }
368
    else {
369
        print $fh 'BGM+220+', $basketno, "+9'";    # print order number
370
    }
371
    print $fh "DTM+137:$longyear$date:102'";       # print date of message
372
    print $fh "NAD+BY+"
373
      . C4::Context->preference("EDIfactEAN")
374
      . "::9'";                                    # print buyer EAN
375
    print $fh 'NAD+SU+', $san,          "::31B'";  # print vendor SAN
376
    print $fh 'NAD+SU+', $booksellerid, "::92'";   # print internal ID
377
378
    # get items from basket
379
    my @results = GetOrders($basketno);
380
    foreach my $item (@results) {
381
        $linecount++;
382
        my $price;
383
        my $title     = string35escape( escape( $item->{title} ) );
384
        my $author    = string35escape( escape( $item->{author} ) );
385
        my $publisher = string35escape( escape( $item->{publishercode} ) );
386
        $price = sprintf '%.2f', $item->{listprice};
387
        my $isbn;
388
        if (   length( $item->{isbn} ) == 10
389
            || substr( $item->{isbn}, 0, 3 ) eq '978'
390
            || index( $item->{isbn}, '|' ) != -1 )
391
        {
392
            $isbn = cleanisbn( $item->{isbn} );
393
            $isbn = Business::ISBN->new($isbn);
394
            if ($isbn) {
395
                if ( $isbn->is_valid ) {
396
                    $isbn = ( $isbn->as_isbn13 )->isbn;
397
                }
398
                else {
399
                    $isbn = '0';
400
                }
401
            }
402
            else {
403
                $isbn = 0;
404
            }
405
        }
406
        else {
407
            $isbn = $item->{isbn};
408
        }
409
        my $copyrightdate = escape( $item->{publicationyear} );
410
        my $quantity      = escape( $item->{quantity} );
411
        my $ordernumber   = escape( $item->{ordernumber} );
412
        my $notes;
413
        if ( $item->{notes} ) {
414
            $notes = $item->{notes};
415
            $notes =~ s/[\r\n]+//g;
416
            $notes = string35escape( escape($notes) );
417
        }
418
419
        my ( $branchcode, $callnumber, $itype, $lsqccode, $fund ) =
420
          GetOrderItemInfo( $item->{'ordernumber'} );
421
        $callnumber = escape($callnumber);
422
423
        print $fh "LIN+$linecount++" . $isbn . ":EN'";    # line number, isbn
424
        print $fh "PIA+5+" . $isbn
425
          . ":IB'";                        # isbn as main product identification
426
        print $fh "IMD+L+050+:::$title'";  # title
427
        print $fh "IMD+L+009+:::$author'"; # full name of author
428
        print $fh "IMD+L+109+:::$publisher'";        # publisher
429
        print $fh "IMD+L+170+:::$copyrightdate'";    # date of publication
430
        print $fh "IMD+L+220+:::O'";    # binding (e.g. PB) (O if not specified)
431
        if ( $callnumber ne '' ) {
432
            print $fh "IMD+L+230+:::$callnumber'";    # shelfmark
433
        }
434
        print $fh "QTY+21:$quantity'";                # quantity
435
        if ( $message_type ne 'QUOTE' && $quantity > 1 ) {
436
            print $fh "GIR+001+$quantity:LQT+$branchcode:LLO+$fund:LFN+"
437
              ;                                       # branchcode, fund code
438
        }
439
        else {
440
            print $fh
441
              "GIR+001+$branchcode:LLO+$fund:LFN+";    # branchcode, fund code
442
        }
443
        if ( $callnumber ne '' ) {
444
            print $fh "$callnumber:LCL+";              # shelfmark
445
        }
446
        print $fh $itype . ":LST+$lsqccode:LSQ'";    # stock category, sequence
447
        if ($notes) {
448
            print $fh "FTX+LIN+++:::$notes'";
449
        }
450
        ###REQUEST ORDERS TO REVISIT
451
#if ($message_type ne 'QUOTE')
452
#{
453
#	print $fh "FTX+LIN++$linecount:10B:28'";													# freetext ** used for request orders to denote priority (to revisit)
454
#}
455
        print $fh "PRI+AAB:$price'";    # price per item
456
        my $currency =
457
            $item->{currency} =~ m/^[[:upper:]]{3}$/
458
          ? $item->{currency}
459
          : $default_currency;
460
        print $fh "CUX+2:$currency:9'";      # currency (e.g. GBP, EUR, USD)
461
        print $fh "RFF+LI:$ordernumber'";    # Local order number
462
        if ( $message_type eq 'QUOTE' ) {
463
            print $fh "RFF+QLI:"
464
              . $item->{booksellerinvoicenumber}
465
              . q{'};   # If QUOTE confirmation, include booksellerinvoicenumber
466
        }
467
    }
468
    print $fh "UNS+S'";              # print summary section header
469
    print $fh "CNT+2:$linecount'";   # print number of line items in the message
470
    my $segments = ( ( $linecount * 13 ) + 9 );
471
    print $fh "UNT+$segments+"
472
      . $ref . "'"
473
      ; # No. of segments in message (UNH+UNT elements included, UNA, UNB, UNZ excluded)
474
        # Message ref number
475
    print $fh "UNZ+1+" . $exchange . "'\n";    # Exchange ref number
476
477
    close $fh;
478
479
    LogEDIFactOrder( $booksellerid, 'Queued', $basketno );
480
481
    return $filename;
482
483
}
484
485
sub GetMessageType {
486
    my $basketno = shift;
487
    my $dbh      = C4::Context->dbh;
488
    my $sth;
489
    my $message_type;
490
    my @row;
491
    $sth = $dbh->prepare(
492
        'select message_type from edifact_messages where basketno=?');
493
    $sth->execute($basketno);
494
    while ( @row = $sth->fetchrow_array() ) {
495
        $message_type = $row[0];
496
    }
497
    return $message_type;
498
}
499
500
sub cleanisbn {
501
    my $isbn = shift;
502
    if ($isbn) {
503
        my $i = index( $isbn, '(' );
504
        if ( $i > 1 ) {
505
            $isbn = substr( $isbn, 0, ( $i - 1 ) );
506
        }
507
        if ( $isbn =~ /\|/ ) {
508
            my @isbns = split( /\|/, $isbn );
509
            $isbn = $isbns[0];
510
        }
511
        $isbn = escape($isbn);
512
        $isbn =~ s/^\s+//;
513
        $isbn =~ s/\s+$//;
514
        return $isbn;
515
    }
516
    return;
517
}
518
519
sub escape {
520
    my $string = shift;
521
    if ($string) {
522
        $string =~ s/\?/\?\?/g;
523
        $string =~ s/\'/\?\'/g;
524
        $string =~ s/\:/\?\:/g;
525
        $string =~ s/\+/\?\+/g;
526
        return $string;
527
    }
528
    return;
529
}
530
531
=head2 GetBranchCode
532
533
Return branchcode for an order when formatting an EDIfact order message
534
535
=cut
536
537
sub GetBranchCode {
538
    my $biblioitemnumber = shift;
539
    my $dbh              = C4::Context->dbh;
540
    my $branchcode;
541
    my @row;
542
    my $sth =
543
      $dbh->prepare("select homebranch from items where biblioitemnumber=?");
544
    $sth->execute($biblioitemnumber);
545
    while ( @row = $sth->fetchrow_array() ) {
546
        $branchcode = $row[0];
547
    }
548
    return $branchcode;
549
}
550
551
=head2 SendEDIOrder
552
553
Transfers an EDIfact order message to the relevant vendor's FTP site
554
555
=cut
556
557
sub SendEDIOrder {
558
    my ( $basketno, $booksellerid ) = @_;
559
    my $newerr;
560
    my $result;
561
562
    # check edi order file exists
563
    my $edi_files = C4::Context->config('intranetdir');
564
    $edi_files .= '/misc/edi_files/';
565
    if ( -e "${edi_files}ediorder_$basketno.CEP" ) {
566
        my $dbh = C4::Context->dbh;
567
        my $sth;
568
        $sth = $dbh->prepare(
569
"select id, host, username, password, provider, in_dir from vendor_edi_accounts where provider=?"
570
        );
571
        $sth->execute($booksellerid);
572
        my $ftpaccount = $sth->fetchrow_hashref;
573
574
        #check vendor edi account exists
575
        if ($ftpaccount) {
576
577
            # connect to ftp account
578
            my $ftp = Net::FTP->new( $ftpaccount->{host}, Timeout => 10 )
579
              or $newerr = 1;
580
            if ( !$newerr ) {
581
                $newerr = 0;
582
583
                # login
584
                $ftp->login( $ftpaccount->{username}, $ftpaccount->{password} )
585
                  or $newerr = 1;
586
                $ftp->quit if $newerr;
587
                if ( !$newerr ) {
588
589
                    # cd to directory
590
                    $ftp->cwd( $ftpaccount->{in_dir} ) or $newerr = 1;
591
                    $ftp->quit if $newerr;
592
593
                    # put file
594
                    if ( !$newerr ) {
595
                        $newerr = 0;
596
                        $ftp->put("${edi_files}ediorder_$basketno.CEP")
597
                          or $newerr = 1;
598
                        $ftp->quit if $newerr;
599
                        if ( !$newerr ) {
600
                            $result =
601
"File: ediorder_$basketno.CEP transferred successfully";
602
                            $ftp->quit;
603
                            unlink "${edi_files}ediorder_$basketno.CEP";
604
                            LogEDITransaction( $ftpaccount->{id} );
605
                            LogEDIFactOrder( $booksellerid, 'Sent', $basketno );
606
                            return $result;
607
                        }
608
                        else {
609
                            $result =
610
"Could not transfer the file ${edi_files}ediorder_$basketno.CEP to $ftpaccount->{host}: $_";
611
                            FTPError($result);
612
                            LogEDIFactOrder( $booksellerid, 'Failed',
613
                                $basketno );
614
                            return $result;
615
                        }
616
                    }
617
                    else {
618
                        $result =
619
"Cannot get remote directory ($ftpaccount->{in_dir}) on $ftpaccount->{host}";
620
                        FTPError($result);
621
                        LogEDIFactOrder( $booksellerid, 'Failed', $basketno );
622
                        return $result;
623
                    }
624
                }
625
                else {
626
                    $result = "Cannot log in to $ftpaccount->{host}: $!";
627
                    FTPError($result);
628
                    LogEDIFactOrder( $booksellerid, 'Failed', $basketno );
629
                    return $result;
630
                }
631
            }
632
            else {
633
                $result =
634
                  "Cannot make an FTP connection to $ftpaccount->{host}: $!";
635
                FTPError($result);
636
                LogEDIFactOrder( $booksellerid, 'Failed', $basketno );
637
                return $result;
638
            }
639
        }
640
        else {
641
            $result =
642
"Vendor ID: $booksellerid does not have a current EDIfact FTP account";
643
            FTPError($result);
644
            LogEDIFactOrder( $booksellerid, 'Failed', $basketno );
645
            return $result;
646
        }
647
    }
648
    else {
649
        $result = 'There is no EDIfact order for this basket';
650
        return $result;
651
    }
652
}
653
654
sub FTPError {
655
    my $error    = shift;
656
    my $log_file = C4::Context->config('intranetdir');
657
    $log_file .= '/misc/edi_files/edi_ftp_error.log';
658
    open my $log_fh, '>>', $log_file
659
      or croak "Could not open $log_file: $!";
660
    my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
661
    printf $log_fh "%4d-%02d-%02d %02d:%02d:%02d\n-----\n",
662
      $year + 1900, $mon + 1, $mday, $hour, $min, $sec;
663
    print $log_fh "$error\n\n";
664
    close $log_fh;
665
    return;
666
}
667
668
=head2 SendQueuedEDIOrders
669
670
Sends all EDIfact orders that are held in the Queued
671
672
=cut
673
674
sub SendQueuedEDIOrders {
675
    my $dbh = C4::Context->dbh;
676
    my @orders;
677
    my $sth = $dbh->prepare(
678
        q|select basketno, provider from edifact_messages where status='Queued'|
679
    );
680
    $sth->execute();
681
    while ( @orders = $sth->fetchrow_array() ) {
682
        SendEDIOrder( $orders[0], $orders[1] );
683
    }
684
    return;
685
}
686
687
=head2 ParseEDIQuote
688
689
Uses Business::Edifact::Interchange to parse a stored EDIfact quote message, creates basket, biblios, biblioitems, and items
690
691
=cut
692
693
sub ParseEDIQuote {
694
    my ( $filename, $booksellerid ) = @_;
695
    my $basketno;
696
    my $ParseEDIQuoteItem;
697
698
    my $edi  = Business::Edifact::Interchange->new;
699
    my $path = C4::Context->config('intranetdir');
700
    $path .= '/misc/edi_files/';
701
    $edi->parse_file("$path$filename");
702
    my $messages = $edi->messages();
703
    my $msg_cnt  = @{$messages};
704
705
    # create default edifact_messages entry
706
    my $messagekey = LogEDIFactQuote( $booksellerid, 'Failed', 0, 0 );
707
708
    #create basket
709
    if ( $msg_cnt > 0 && $booksellerid ) {
710
        $basketno = NewBasket( $booksellerid, 0, $filename, q{}, q{}, q{} );
711
    }
712
713
    $ParseEDIQuoteItem = sub {
714
        my ( $item, $gir, $bookseller_id ) = @_;
715
        my $relnos = $item->{related_numbers};
716
        my $author = $item->author_surname . ", " . $item->author_firstname;
717
718
        my $ecost =
719
          GetDiscountedPrice( $bookseller_id, $item->{price}->{price} );
720
721
        my $ftxlin;
722
        my $ftxlno;
723
        if ( $item->{free_text}->{qualifier} eq 'LIN' ) {
724
            $ftxlin = $item->{free_text}->{text};
725
        }
726
        if ( $item->{free_text}->{qualifier} eq 'LNO' ) {
727
            $ftxlno = $item->{free_text}->{text};
728
        }
729
730
        my ( $llo, $lfn, $lsq, $lst, $lfs, $lcl, $id );
731
        my $relcount = 0;
732
        foreach my $rel ( @{$relnos} ) {
733
            if ( $rel->{id} == ( $gir + 1 ) ) {
734
                if ( $item->{related_numbers}->[$relcount]->{LLO}->[0] ) {
735
                    $llo = $item->{related_numbers}->[$relcount]->{LLO}->[0];
736
                }
737
                if ( $item->{related_numbers}->[$relcount]->{LFN}->[0] ) {
738
                    $lfn = $item->{related_numbers}->[$relcount]->{LFN}->[0];
739
                }
740
                if ( $item->{related_numbers}->[$relcount]->{LSQ}->[0] ) {
741
                    $lsq = $item->{related_numbers}->[$relcount]->{LSQ}->[0];
742
                }
743
                if ( $item->{related_numbers}->[$relcount]->{LST}->[0] ) {
744
                    $lst = $item->{related_numbers}->[$relcount]->{LST}->[0];
745
                }
746
                if ( $item->{related_numbers}->[$relcount]->{LFS}->[0] ) {
747
                    $lfs = $item->{related_numbers}->[$relcount]->{LFS}->[0];
748
                }
749
                if ( $item->{related_numbers}->[$relcount]->{LCL}->[0] ) {
750
                    $lcl = $item->{related_numbers}->[$relcount]->{LCL}->[0];
751
                }
752
                if ( $item->{related_numbers}->[$relcount]->{id} ) {
753
                    $id = $item->{related_numbers}->[$relcount]->{id};
754
                }
755
            }
756
            $relcount++;
757
        }
758
759
        my $lclnote;
760
        if ( !$lst ) {
761
            $lst = uc( $item->item_format );
762
        }
763
        if ( !$lcl ) {
764
            $lcl = $item->shelfmark;
765
        }
766
        else {
767
            ( $lcl, $lclnote ) = DawsonsLCL($lcl);
768
        }
769
        if ($lfs) {
770
            $lcl .= " $lfs";
771
        }
772
773
        my $budget_id = GetBudgetID($lfn);
774
775
     #Uncomment section below to define a default budget_id if there is no match
776
     #if (!defined $budget_id)
777
     #{
778
     #	$budget_id=0;
779
     #}
780
781
        # create biblio record
782
        my $bib_record = TransformKohaToMarc(
783
            {
784
                'biblio.title'       => $item->title,
785
                'biblio.author'      => $author ? $author : q{},
786
                'biblio.seriestitle' => q{},
787
                'biblioitems.isbn'   => $item->{item_number}
788
                ? $item->{item_number}
789
                : q{},
790
                'biblioitems.publishercode' => $item->publisher
791
                ? $item->publisher
792
                : q{},
793
                'biblioitems.publicationyear' => $item->date_of_publication
794
                ? $item->date_of_publication
795
                : q{},
796
                'biblio.copyrightdate' => $item->date_of_publication
797
                ? $item->date_of_publication
798
                : q{},
799
                'biblioitems.itemtype'  => uc( $item->item_format ),
800
                'biblioitems.cn_source' => 'ddc',
801
                'items.cn_source'       => 'ddc',
802
                'items.notforloan'      => -1,
803
804
                #"items.ccode"				  => $lsq,
805
                'items.location'         => $lsq,
806
                'items.homebranch'       => $llo,
807
                'items.holdingbranch'    => $llo,
808
                'items.booksellerid'     => $bookseller_id,
809
                'items.price'            => $item->{price}->{price},
810
                'items.replacementprice' => $item->{price}->{price},
811
                'items.itemcallnumber'   => $lcl,
812
                'items.itype'            => $lst,
813
                'items.cn_sort'          => q{},
814
            }
815
        );
816
817
        #check if item already exists in catalogue
818
        my $biblionumber;
819
        my $bibitemnumber;
820
        ( $biblionumber, $bibitemnumber ) =
821
          CheckOrderItemExists( $item->{item_number} );
822
823
        if ( !defined $biblionumber ) {
824
825
            # create the record in catalogue, with framework ''
826
            ( $biblionumber, $bibitemnumber ) = AddBiblio( $bib_record, q{} );
827
        }
828
829
        my $ordernote;
830
        if ($lclnote) {
831
            $ordernote = $lclnote;
832
        }
833
        if ($ftxlno) {
834
            $ordernote = $ftxlno;
835
        }
836
        if ($ftxlin) {
837
            $ordernote = $ftxlin;
838
        }
839
840
        my %orderinfo = (
841
            basketno                => $basketno,
842
            ordernumber             => q{},
843
            subscription            => 'no',
844
            uncertainprice          => 0,
845
            biblionumber            => $biblionumber,
846
            title                   => $item->title,
847
            quantity                => 1,
848
            biblioitemnumber        => $bibitemnumber,
849
            rrp                     => $item->{price}->{price},
850
            ecost                   => $ecost,
851
            sort1                   => q{},
852
            sort2                   => q{},
853
            booksellerinvoicenumber => $item->{item_reference}[0][1],
854
            listprice               => $item->{price}->{price},
855
            branchcode              => $llo,
856
            budget_id               => $budget_id,
857
            notes                   => $ordernote,
858
        );
859
860
        my $orderinfo = \%orderinfo;
861
862
        my ( $retbasketno, $ordernumber ) = NewOrder($orderinfo);
863
864
        # now, add items if applicable
865
        if ( C4::Context->preference('AcqCreateItem') eq 'ordering' ) {
866
            my $itemnumber;
867
            ( $biblionumber, $bibitemnumber, $itemnumber ) =
868
              AddItemFromMarc( $bib_record, $biblionumber );
869
            NewOrderItem( $itemnumber, $ordernumber );
870
        }
871
    };
872
873
    for ( my $count = 0 ; $count < $msg_cnt ; $count++ ) {
874
        my $items   = $messages->[$count]->items();
875
        my $ref_num = $messages->[$count]->{ref_num};
876
877
        foreach my $item ( @{$items} ) {
878
            for ( my $i = 0 ; $i < $item->{quantity} ; $i++ ) {
879
                &$ParseEDIQuoteItem( $item, $i, $booksellerid, $basketno );
880
            }
881
        }
882
    }
883
884
    # update edifact_messages entry
885
    LogEDIFactQuote( $booksellerid, 'Received', $basketno, $messagekey );
886
    return 1;
887
888
}
889
890
=head2 GetDiscountedPrice
891
892
Returns the discounted price for an order based on the discount rate for a given vendor
893
894
=cut
895
896
sub GetDiscountedPrice {
897
    my ( $booksellerid, $price ) = @_;
898
    my $dbh = C4::Context->dbh;
899
    my $sth;
900
    my @discount;
901
    my $ecost;
902
    my $percentage;
903
    $sth = $dbh->prepare(q|select discount from aqbooksellers where id=?|);
904
    $sth->execute($booksellerid);
905
906
    while ( @discount = $sth->fetchrow_array() ) {
907
        $percentage = $discount[0];
908
    }
909
    $ecost = ( $price - ( ( $percentage * $price ) / 100 ) );
910
    return $ecost;
911
}
912
913
=head2 DawsonsLCL
914
915
Checks for a call number encased by asterisks. If found, returns call number as $lcl and string with
916
asterisks as $lclnote to go into FTX field enabling spine label creation by Dawsons bookseller
917
918
=cut
919
920
sub DawsonsLCL {
921
    my $lcl = shift;
922
    my $lclnote;
923
    my $f = index( $lcl, '*' );
924
    my $l = rindex( $lcl, '*' );
925
    if ( $f == 0 && $l == ( length($lcl) - 1 ) ) {
926
        $lclnote = $lcl;
927
        $lcl =~ s/\*//g;
928
    }
929
    return ( $lcl, $lclnote );
930
}
931
932
=head2 GetBudgetID
933
934
Returns the budget_id for a given budget_code
935
936
=cut
937
938
sub GetBudgetID {
939
    my $fundcode = shift;
940
    my $dbh      = C4::Context->dbh;
941
    my @funds;
942
    my $ecost;
943
    my $budget_id;
944
    my $sth =
945
      $dbh->prepare('select budget_id from aqbudgets where budget_code=?');
946
    $sth->execute($fundcode);
947
948
    while ( @funds = $sth->fetchrow_array() ) {
949
        $budget_id = $funds[0];
950
    }
951
    return $budget_id;
952
}
953
954
=head2 CheckOrderItemExists
955
956
Checks to see if a biblio record already exists in the catalogue when parsing a quotes message
957
Converts 10-13 digit ISBNs and vice-versa if an initial match is not found
958
959
=cut
960
961
sub CheckOrderItemExists {
962
    my $isbn = shift;
963
    my $dbh  = C4::Context->dbh;
964
    my @matches;
965
    my $biblionumber;
966
    my $bibitemnumber;
967
    my $sth = $dbh->prepare(
968
        'select biblionumber, biblioitemnumber from biblioitems where isbn=?');
969
    $sth->execute($isbn);
970
971
    while ( @matches = $sth->fetchrow_array() ) {
972
        $biblionumber  = $matches[0];
973
        $bibitemnumber = $matches[1];
974
    }
975
    if ($biblionumber) {
976
        return $biblionumber, $bibitemnumber;
977
    }
978
    else {
979
        $isbn = cleanisbn($isbn);
980
        if ( length($isbn) == 10 ) {
981
            $isbn = Business::ISBN->new($isbn);
982
            if ($isbn) {
983
                if ( $isbn->is_valid ) {
984
                    $isbn = ( $isbn->as_isbn13 )->isbn;
985
                    $sth->execute($isbn);
986
                    while ( @matches = $sth->fetchrow_array() ) {
987
                        $biblionumber  = $matches[0];
988
                        $bibitemnumber = $matches[1];
989
                    }
990
                }
991
            }
992
        }
993
        elsif ( length($isbn) == 13 ) {
994
            $isbn = Business::ISBN->new($isbn);
995
            if ($isbn) {
996
                if ( $isbn->is_valid ) {
997
                    $isbn = ( $isbn->as_isbn10 )->isbn;
998
                    $sth->execute($isbn);
999
                    while ( @matches = $sth->fetchrow_array() ) {
1000
                        $biblionumber  = $matches[0];
1001
                        $bibitemnumber = $matches[1];
1002
                    }
1003
                }
1004
            }
1005
        }
1006
        return $biblionumber, $bibitemnumber;
1007
    }
1008
}
1009
1010
sub string35escape {
1011
    my $string = shift;
1012
    my $colon_string;
1013
    my @sections;
1014
    if ( length($string) > 35 ) {
1015
        my ( $chunk, $stringlength ) = ( 35, length($string) );
1016
        for ( my $counter = 0 ; $counter < $stringlength ; $counter += $chunk )
1017
        {
1018
            push @sections, substr( $string, $counter, $chunk );
1019
        }
1020
        foreach my $section (@sections) {
1021
            $colon_string .= "$section:";
1022
        }
1023
        chop $colon_string;
1024
    }
1025
    else {
1026
        $colon_string = $string;
1027
    }
1028
    return $colon_string;
1029
}
1030
1031
sub GetOrderItemInfo {
1032
    my $ordernumber = shift;
1033
    my $dbh         = C4::Context->dbh;
1034
    my @rows;
1035
    my $homebranch;
1036
    my $callnumber;
1037
    my $itype;
1038
    my $ccode;
1039
    my $fund;
1040
    my $sth = $dbh->prepare(
1041
q|select items.homebranch, items.itemcallnumber, items.itype, items.location from items
1042
 inner join aqorders_items on aqorders_items.itemnumber=items.itemnumber
1043
 where aqorders_items.ordernumber=?|
1044
    );
1045
    $sth->execute($ordernumber);
1046
1047
    while ( @rows = $sth->fetchrow_array() ) {
1048
        $homebranch = $rows[0];
1049
        $callnumber = $rows[1];
1050
        $itype      = $rows[2];
1051
        $ccode      = $rows[3];
1052
    }
1053
    $sth = $dbh->prepare(
1054
        q|select aqbudgets.budget_code from aqbudgets inner join aqorders on
1055
 aqorders.budget_id=aqbudgets.budget_id where aqorders.ordernumber=?|
1056
    );
1057
    $sth->execute($ordernumber);
1058
    while ( @rows = $sth->fetchrow_array() ) {
1059
        $fund = $rows[0];
1060
    }
1061
    return $homebranch, $callnumber, $itype, $ccode, $fund;
1062
}
1063
1064
sub CheckVendorFTPAccountExists {
1065
    my $booksellerid = shift;
1066
    my $dbh          = C4::Context->dbh;
1067
    my $sth          = $dbh->prepare(
1068
        q|select count(id) from vendor_edi_accounts where provider=?|);
1069
    $sth->execute($booksellerid);
1070
    while ( my @rows = $sth->fetchrow_array() ) {
1071
        if ( $rows[0] > 0 ) {
1072
            return 1;
1073
        }
1074
    }
1075
    return;
1076
}
1077
1078
1;
1079
1080
__END__
1081
1082
=head1 AUTHOR
1083
1084
Mark Gavillet
1085
1086
=cut
(-)a/acqui/basket.pl (+12 lines)
Lines 28-33 use C4::Output; Link Here
28
use CGI;
28
use CGI;
29
use C4::Acquisition;
29
use C4::Acquisition;
30
use C4::Budgets;
30
use C4::Budgets;
31
use C4::EDI qw( CreateEDIOrder SendEDIOrder );
31
use C4::Bookseller qw( GetBookSellerFromId);
32
use C4::Bookseller qw( GetBookSellerFromId);
32
use C4::Debug;
33
use C4::Debug;
33
use C4::Biblio;
34
use C4::Biblio;
Lines 86-91 my $basket = GetBasket($basketno); Link Here
86
# if no booksellerid in parameter, get it from basket
87
# if no booksellerid in parameter, get it from basket
87
# warn "=>".$basket->{booksellerid};
88
# warn "=>".$basket->{booksellerid};
88
$booksellerid = $basket->{booksellerid} unless $booksellerid;
89
$booksellerid = $basket->{booksellerid} unless $booksellerid;
90
my $ediaccount = CheckVendorFTPAccountExists($booksellerid);
91
$template->param(ediaccount=>$ediaccount);
89
my ($bookseller) = GetBookSellerFromId($booksellerid);
92
my ($bookseller) = GetBookSellerFromId($booksellerid);
90
my $op = $query->param('op');
93
my $op = $query->param('op');
91
if (!defined $op) {
94
if (!defined $op) {
Lines 95-100 if (!defined $op) { Link Here
95
my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
98
my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
96
$template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
99
$template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
97
100
101
if ( $op eq 'ediorder') {
102
	my $edifile=CreateEDIOrder($basketno,$booksellerid);
103
	$template->param(edifile => $edifile);
104
}
105
if ( $op eq 'edisend') {
106
	my $edisend=SendEDIOrder($basketno,$booksellerid);
107
	$template->param(edisend => $edisend);
108
}
109
98
if ( $op eq 'delete_confirm' ) {
110
if ( $op eq 'delete_confirm' ) {
99
    my $basketno = $query->param('basketno');
111
    my $basketno = $query->param('basketno');
100
    DelBasket($basketno);
112
    DelBasket($basketno);
(-)a/admin/edi-accounts.pl (+72 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011,2012 Mark Gavillet & PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use CGI;
23
use C4::Auth;
24
use C4::Output;
25
use C4::EDI
26
  qw( CreateEDIDetails UpdateEDIDetails GetEDIAccounts DeleteEDIDetails);
27
28
my $input = CGI->new();
29
30
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
31
    {
32
        template_name   => 'admin/edi-accounts.tmpl',
33
        query           => $input,
34
        type            => 'intranet',
35
        authnotrequired => 0,
36
        flagsrequired   => { borrowers => 1 },
37
    }
38
);
39
40
my $op = $input->param('op');
41
$template->param( op => $op );
42
43
if ( $op eq 'delsubmit' ) {
44
    my $del = DeleteEDIDetails( $input->param('id') );
45
    $template->param( opdelsubmit => 1 );
46
}
47
48
if ( $op eq 'addsubmit' ) {
49
    CreateEDIDetails(
50
        $input->param('provider'), $input->param('description'),
51
        $input->param('host'),     $input->param('user'),
52
        $input->param('pass'),     $input->param('path'),
53
        $input->param('in_dir'),   $input->param('san')
54
    );
55
    $template->param( opaddsubmit => 1 );
56
}
57
58
if ( $op eq 'editsubmit' ) {
59
    UpdateEDIDetails(
60
        $input->param('editid'), $input->param('description'),
61
        $input->param('host'),   $input->param('user'),
62
        $input->param('pass'),   $input->param('provider'),
63
        $input->param('path'),   $input->param('in_dir'),
64
        $input->param('san')
65
    );
66
    $template->param( opeditsubmit => 1 );
67
}
68
69
my $ediaccounts = GetEDIAccounts();
70
$template->param( ediaccounts => $ediaccounts );
71
72
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/admin/edi-edit.pl (+75 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011 Mark Gavillet & PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use CGI;
23
use C4::Auth;
24
use C4::Output;
25
use C4::EDI qw( GetVendorList GetEDIAccountDetails);
26
27
my $input = CGI->new();
28
29
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
30
    {
31
        template_name   => 'admin/edi-edit.tmpl',
32
        query           => $input,
33
        type            => 'intranet',
34
        authnotrequired => 0,
35
        flagsrequired   => { borrowers => 1 },
36
    }
37
);
38
my $vendorlist = GetVendorList();
39
40
my $op = $input->param('op');
41
$template->param( op => $op );
42
43
if ( $op eq 'add' ) {
44
    $template->param( opaddsubmit => 'addsubmit' );
45
}
46
if ( $op eq 'edit' ) {
47
    $template->param( opeditsubmit => 'editsubmit' );
48
    my $edi_details      = GetEDIAccountDetails( $input->param('id') );
49
    my $selectedprovider = $edi_details->{provider};
50
    foreach my $prov (@$vendorlist) {
51
        $prov->{selected} = 'selected'
52
          if $prov->{id} == $selectedprovider;
53
    }
54
    $template->param(
55
        editid      => $edi_details->{id},
56
        description => $edi_details->{description},
57
        host        => $edi_details->{host},
58
        user        => $edi_details->{username},
59
        pass        => $edi_details->{password},
60
        provider    => $edi_details->{provider},
61
        in_dir      => $edi_details->{in_dir},
62
        san         => $edi_details->{san}
63
    );
64
}
65
if ( $op eq 'del' ) {
66
    $template->param(
67
        opdelsubmit => 'delsubmit',
68
        opdel       => 1,
69
        id          => $input->param('id')
70
    );
71
}
72
73
$template->param( vendorlist => $vendorlist );
74
75
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/installer/data/mysql/atomicupdate/edifact.sql (+27 lines)
Line 0 Link Here
1
CREATE TABLE IF NOT EXISTS vendor_edi_accounts (
2
  id int(11) NOT NULL auto_increment,
3
  description text NOT NULL,
4
  host text,
5
  username text,
6
  password text,
7
  last_activity date default NULL,
8
  provider int(11) default NULL,
9
  in_dir text,
10
  san varchar(10) default NULL,
11
  PRIMARY KEY  (id)
12
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
13
14
CREATE TABLE IF NOT EXISTS edifact_messages (
15
  id int(11) NOT NULL auto_increment,
16
  message_type text NOT NULL,
17
  date_sent date default NULL,
18
  provider int(11) default NULL,
19
  status text,
20
  basketno int(11) NOT NULL default '0',
21
  PRIMARY KEY  (id)
22
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
23
24
insert into permissions (module_bit, code, description) values (13, 'edi_manage', 'Manage EDIFACT transmissions');
25
26
INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES
27
('EDIfactEAN', '56781234', '', 'EAN identifier for the library used in EDIfact messages', 'Textarea');
(-)a/installer/data/mysql/de-DE/mandatory/userpermissions.sql (+1 lines)
Lines 43-48 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
43
   (13, 'moderate_tags', 'Von Benutzern vergebene Tags moderieren'),
43
   (13, 'moderate_tags', 'Von Benutzern vergebene Tags moderieren'),
44
   (13, 'rotating_collections', 'Wandernde Sammlungen verwalten'),
44
   (13, 'rotating_collections', 'Wandernde Sammlungen verwalten'),
45
   (13, 'upload_local_cover_images', 'Eigene Coverbilder hochladen'),
45
   (13, 'upload_local_cover_images', 'Eigene Coverbilder hochladen'),
46
   (13, 'edi_manage', 'Manage EDIFACT transmissions'),
46
   (15, 'check_expiration', 'Ablauf eines Abonnements prüfen'),
47
   (15, 'check_expiration', 'Ablauf eines Abonnements prüfen'),
47
   (15, 'claim_serials', 'Fehlende Hefte reklamieren'),
48
   (15, 'claim_serials', 'Fehlende Hefte reklamieren'),
48
   (15, 'create_subscription', 'Neues Abonnement anlegen'),
49
   (15, 'create_subscription', 'Neues Abonnement anlegen'),
(-)a/installer/data/mysql/en/mandatory/userpermissions.sql (+1 lines)
Lines 43-48 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
43
   (13, 'moderate_tags', 'Moderate patron tags'),
43
   (13, 'moderate_tags', 'Moderate patron tags'),
44
   (13, 'rotating_collections', 'Manage rotating collections'),
44
   (13, 'rotating_collections', 'Manage rotating collections'),
45
   (13, 'upload_local_cover_images', 'Upload local cover images'),
45
   (13, 'upload_local_cover_images', 'Upload local cover images'),
46
   (13, 'edi_manage', 'Manage EDIFACT transmissions'),
46
   (15, 'check_expiration', 'Check the expiration of a serial'),
47
   (15, 'check_expiration', 'Check the expiration of a serial'),
47
   (15, 'claim_serials', 'Claim missing serials'),
48
   (15, 'claim_serials', 'Claim missing serials'),
48
   (15, 'create_subscription', 'Create a new subscription'),
49
   (15, 'create_subscription', 'Create a new subscription'),
(-)a/installer/data/mysql/es-ES/mandatory/userpermissions.sql (+1 lines)
Lines 43-48 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
43
   (13, 'moderate_tags', 'Moderate patron tags'),
43
   (13, 'moderate_tags', 'Moderate patron tags'),
44
   (13, 'rotating_collections', 'Manage rotating collections'),
44
   (13, 'rotating_collections', 'Manage rotating collections'),
45
   (13, 'upload_local_cover_images', 'Upload local cover images'),
45
   (13, 'upload_local_cover_images', 'Upload local cover images'),
46
   (13, 'edi_manage', 'Manage EDIFACT transmissions'),
46
   (15, 'check_expiration', 'Check the expiration of a serial'),
47
   (15, 'check_expiration', 'Check the expiration of a serial'),
47
   (15, 'claim_serials', 'Claim missing serials'),
48
   (15, 'claim_serials', 'Claim missing serials'),
48
   (15, 'create_subscription', 'Create a new subscription'),
49
   (15, 'create_subscription', 'Create a new subscription'),
(-)a/installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql (+1 lines)
Lines 43-48 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
43
   (13, 'items_batchmod', 'Modifier les exemplaires par lot'),
43
   (13, 'items_batchmod', 'Modifier les exemplaires par lot'),
44
   (13, 'items_batchdel', 'Supprimer les exemplaires par lot'),
44
   (13, 'items_batchdel', 'Supprimer les exemplaires par lot'),
45
   (13, 'upload_local_cover_images', 'Téléchargement des images de couverture'),
45
   (13, 'upload_local_cover_images', 'Téléchargement des images de couverture'),
46
   (13, 'edi_manage', 'Manage EDIFACT transmissions'),
46
   (15, 'check_expiration', 'Contrôler l''expiration d''un périodique'),
47
   (15, 'check_expiration', 'Contrôler l''expiration d''un périodique'),
47
   (15, 'claim_serials', 'Réclamer les périodiques manquants'),
48
   (15, 'claim_serials', 'Réclamer les périodiques manquants'),
48
   (15, 'create_subscription', 'Créer de nouveaux abonnements'),
49
   (15, 'create_subscription', 'Créer de nouveaux abonnements'),
(-)a/installer/data/mysql/it-IT/necessari/userpermissions.sql (+1 lines)
Lines 45-50 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
45
   (13, 'moderate_tags', 'Modera i tag inseriti dagli utenti'),
45
   (13, 'moderate_tags', 'Modera i tag inseriti dagli utenti'),
46
   (13, 'rotating_collections', 'Gestisci le collezioni circolanti (rotating collections)'),
46
   (13, 'rotating_collections', 'Gestisci le collezioni circolanti (rotating collections)'),
47
   (13, 'upload_local_cover_images', 'Carica copertine in locale'),
47
   (13, 'upload_local_cover_images', 'Carica copertine in locale'),
48
   (13, 'edi_manage', 'Manage EDIFACT transmissions'),
48
   (15, 'check_expiration', 'Controlla la scadenza di una risora in continuazione'),
49
   (15, 'check_expiration', 'Controlla la scadenza di una risora in continuazione'),
49
   (15, 'claim_serials', 'Richiedi i fascicoli non arrivati'),
50
   (15, 'claim_serials', 'Richiedi i fascicoli non arrivati'),
50
   (15, 'create_subscription', 'Crea un nuovo abbonamento'),
51
   (15, 'create_subscription', 'Crea un nuovo abbonamento'),
(-)a/installer/data/mysql/kohastructure.sql (+29 lines)
Lines 3041-3046 CREATE TABLE IF NOT EXISTS `borrower_modifications` ( Link Here
3041
  PRIMARY KEY (`verification_token`,`borrowernumber`),
3041
  PRIMARY KEY (`verification_token`,`borrowernumber`),
3042
  KEY `verification_token` (`verification_token`),
3042
  KEY `verification_token` (`verification_token`),
3043
  KEY `borrowernumber` (`borrowernumber`)
3043
  KEY `borrowernumber` (`borrowernumber`)
3044
3045
--
3046
-- Table structure for table `vendor_edi_accounts`
3047
--
3048
3049
CREATE TABLE IF NOT EXISTS vendor_edi_accounts (
3050
  id int(11) NOT NULL auto_increment,
3051
  description text NOT NULL,
3052
  host text,
3053
  username text,
3054
  password text,
3055
  last_activity date default NULL,
3056
  provider int(11) default NULL,
3057
  in_dir text,
3058
  san varchar(10) default NULL,
3059
  PRIMARY KEY  (id)
3060
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3061
3062
--
3063
-- Table structure for table `edifact_messages`
3064
--
3065
CREATE TABLE IF NOT EXISTS edifact_messages (
3066
  id int(11) NOT NULL auto_increment,
3067
  message_type text NOT NULL,
3068
  date_sent date default NULL,
3069
  provider int(11) default NULL,
3070
  status text,
3071
  basketno int(11) NOT NULL default '0',
3072
  PRIMARY KEY  (id)
3044
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3073
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3045
3074
3046
--
3075
--
(-)a/installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql (+1 lines)
Lines 63-68 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
63
   (13, 'moderate_tags', 'Behandle tagger fra lånere'),
63
   (13, 'moderate_tags', 'Behandle tagger fra lånere'),
64
   (13, 'rotating_collections', 'Administrere roterende samlinger'),
64
   (13, 'rotating_collections', 'Administrere roterende samlinger'),
65
   (13, 'upload_local_cover_images', 'Laste opp lokale omslagsbilder'),
65
   (13, 'upload_local_cover_images', 'Laste opp lokale omslagsbilder'),
66
   (13, 'edi_manage', 'Manage EDIFACT transmissions'),
66
   (15, 'check_expiration', 'Sjekke utløpsdato for et periodikum'),
67
   (15, 'check_expiration', 'Sjekke utløpsdato for et periodikum'),
67
   (15, 'claim_serials', 'Purre manglende tidsskrifthefter'),
68
   (15, 'claim_serials', 'Purre manglende tidsskrifthefter'),
68
   (15, 'create_subscription', 'Opprette abonnementer'),
69
   (15, 'create_subscription', 'Opprette abonnementer'),
(-)a/installer/data/mysql/pl-PL/mandatory/userpermissions.sql (+1 lines)
Lines 44-49 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
44
   (16, 'execute_reports', 'Execute SQL reports'),
44
   (16, 'execute_reports', 'Execute SQL reports'),
45
   (13, 'rotating_collections', 'Manage rotating collections'),
45
   (13, 'rotating_collections', 'Manage rotating collections'),
46
   (13, 'upload_local_cover_images', 'Upload local cover images'),
46
   (13, 'upload_local_cover_images', 'Upload local cover images'),
47
   (13, 'edi_manage', 'Manage EDIFACT transmissions'),
47
   (15, 'check_expiration', 'Check the expiration of a serial'),
48
   (15, 'check_expiration', 'Check the expiration of a serial'),
48
   (15, 'claim_serials', 'Claim missing serials'),
49
   (15, 'claim_serials', 'Claim missing serials'),
49
   (15, 'create_subscription', 'Create a new subscription'),
50
   (15, 'create_subscription', 'Create a new subscription'),
(-)a/installer/data/mysql/ru-RU/mandatory/permissions_and_user_flags.sql (+1 lines)
Lines 67-72 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
67
   (13, 'moderate_tags', 'Moderate patron tags'),
67
   (13, 'moderate_tags', 'Moderate patron tags'),
68
   (13, 'rotating_collections', 'Manage rotating collections'),
68
   (13, 'rotating_collections', 'Manage rotating collections'),
69
   (13, 'upload_local_cover_images', 'Upload local cover images'),
69
   (13, 'upload_local_cover_images', 'Upload local cover images'),
70
   (13, 'edi_manage',                  'Manage EDIFACT transmissions'),
70
   (15, 'check_expiration',            'Check the expiration of a serial'),
71
   (15, 'check_expiration',            'Check the expiration of a serial'),
71
   (15, 'claim_serials',               'Claim missing serials'),
72
   (15, 'claim_serials',               'Claim missing serials'),
72
   (15, 'create_subscription',         'Create a new subscription'),
73
   (15, 'create_subscription',         'Create a new subscription'),
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 418-420 INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) V Link Here
418
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('UseQueryParser', '0', 'If enabled, try to use QueryParser for queries.', NULL, 'YesNo');
418
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('UseQueryParser', '0', 'If enabled, try to use QueryParser for queries.', NULL, 'YesNo');
419
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('FinesIncludeGracePeriod','1','If enabled, fines calculations will include the grace period.',NULL,'YesNo');
419
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('FinesIncludeGracePeriod','1','If enabled, fines calculations will include the grace period.',NULL,'YesNo');
420
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('UNIMARCAuthorsFacetsSeparator',', ', 'UNIMARC authors facets separator', NULL, 'short');
420
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('UNIMARCAuthorsFacetsSeparator',', ', 'UNIMARC authors facets separator', NULL, 'short');
421
INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES('EDIfactEAN', '56781234', '', 'EAN identifier for the library used in EDIfact messages', 'Textarea');
(-)a/installer/data/mysql/uk-UA/mandatory/permissions_and_user_flags.sql (+1 lines)
Lines 67-72 INSERT INTO permissions (module_bit, code, description) VALUES Link Here
67
   (13, 'moderate_tags', 'Moderate patron tags'),
67
   (13, 'moderate_tags', 'Moderate patron tags'),
68
   (13, 'rotating_collections', 'Manage rotating collections'),
68
   (13, 'rotating_collections', 'Manage rotating collections'),
69
   (13, 'upload_local_cover_images', 'Upload local cover images'),
69
   (13, 'upload_local_cover_images', 'Upload local cover images'),
70
   (13, 'edi_manage',                  'Manage EDIFACT transmissions'),
70
   (15, 'check_expiration',            'Check the expiration of a serial'),
71
   (15, 'check_expiration',            'Check the expiration of a serial'),
71
   (15, 'claim_serials',               'Claim missing serials'),
72
   (15, 'claim_serials',               'Claim missing serials'),
72
   (15, 'create_subscription',         'Create a new subscription'),
73
   (15, 'create_subscription',         'Create a new subscription'),
(-)a/installer/data/mysql/updatedatabase.pl (+47 lines)
Lines 6557-6562 if ( CheckVersion($DBversion) ) { Link Here
6557
    SetVersion($DBversion);
6557
    SetVersion($DBversion);
6558
}
6558
}
6559
6559
6560
$DBversion = "3.09.00.XXX";
6561
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
6562
    print "Upgrade to $DBversion done (Add tables for EDI EDIfact ordering)\n";
6563
my $sql1 = <<"END_EDI1";
6564
CREATE TABLE IF NOT EXISTS vendor_edi_accounts (
6565
  id int(11) NOT NULL auto_increment,
6566
  description text NOT NULL,
6567
  host text,
6568
  username text,
6569
  password text,
6570
  last_activity date default NULL,
6571
  provider int(11) default NULL,
6572
  in_dir text,
6573
  san varchar(10) default NULL,
6574
  PRIMARY KEY  (id)
6575
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
6576
END_EDI1
6577
6578
my $sql2 = <<"END_EDI2";
6579
CREATE TABLE IF NOT EXISTS edifact_messages (
6580
  id int(11) NOT NULL auto_increment,
6581
  message_type text NOT NULL,
6582
  date_sent date default NULL,
6583
  provider int(11) default NULL,
6584
  status text,
6585
  basketno int(11) NOT NULL default '0',
6586
  PRIMARY KEY  (id)
6587
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
6588
END_EDI2
6589
6590
my $sql3 = <<"END_EDI3";
6591
insert into permissions (module_bit, code, description) values (13, 'edi_manage', 'Manage EDIFACT transmissions');
6592
END_EDI3
6593
6594
my $sql4 = <<"END_EDI4";
6595
INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES
6596
('EDIfactEAN', '56781234', '', 'EAN identifier for the library used in EDIfact messages', 'Textarea');
6597
END_EDI4
6598
6599
    $dbh->do($sql1);
6600
    $dbh->do($sql2);
6601
    $dbh->do($sql3);
6602
    $dbh->do($sql4);
6603
6604
    SetVersion($DBversion);
6605
}
6606
6560
=head1 FUNCTIONS
6607
=head1 FUNCTIONS
6561
6608
6562
=head2 TableExists($table)
6609
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc (+1 lines)
Lines 63-68 Link Here
63
	<!-- <li><a href="/cgi-bin/koha/admin/printers.pl">Network Printers</a></li> -->
63
	<!-- <li><a href="/cgi-bin/koha/admin/printers.pl">Network Printers</a></li> -->
64
    <li><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50 client targets</a></li>
64
    <li><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50 client targets</a></li>
65
    <li><a href="/cgi-bin/koha/admin/didyoumean.pl">Did you mean?</a></li>
65
    <li><a href="/cgi-bin/koha/admin/didyoumean.pl">Did you mean?</a></li>
66
	<li><a href="/cgi-bin/koha/admin/edi-accounts.pl">EDI Accounts</a></li>
66
</ul>
67
</ul>
67
</div>
68
</div>
68
</div>
69
</div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc (-1 / +4 lines)
Lines 23-29 Link Here
23
    [% IF ( CAN_user_tools_import_patrons ) %]
23
    [% IF ( CAN_user_tools_import_patrons ) %]
24
	<li><a href="/cgi-bin/koha/tools/import_borrowers.pl">Import patrons</a></li>
24
	<li><a href="/cgi-bin/koha/tools/import_borrowers.pl">Import patrons</a></li>
25
    [% END %]
25
    [% END %]
26
    [% IF ( CAN_user_tools_edit_notices ) %]
26
    [% IF CAN_user_tools_edit_notices %]
27
    <li><a href="/cgi-bin/koha/tools/letter.pl">Notices &amp; slips</a></li>
27
    <li><a href="/cgi-bin/koha/tools/letter.pl">Notices &amp; slips</a></li>
28
    [% END %]
28
    [% END %]
29
    [% IF ( CAN_user_tools_edit_notice_status_triggers ) %]
29
    [% IF ( CAN_user_tools_edit_notice_status_triggers ) %]
Lines 98-101 Link Here
98
    [% IF ( CAN_user_tools_edit_quotes ) %]
98
    [% IF ( CAN_user_tools_edit_quotes ) %]
99
       <li><a href="/cgi-bin/koha/tools/quotes.pl">Quote editor</a></li>
99
       <li><a href="/cgi-bin/koha/tools/quotes.pl">Quote editor</a></li>
100
    [% END %]
100
    [% END %]
101
    [% IF ( CAN_user_tools_edi_manage ) %]
102
	<li><a href="/cgi-bin/koha/tools/edi.pl">EDIfact messages</a></li>
103
    [% END %]
101
</ul></div></div>
104
</ul></div></div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt (-1 / +10 lines)
Lines 146-151 Link Here
146
                            new YAHOO.widget.Button("basketheadbutton");
146
                            new YAHOO.widget.Button("basketheadbutton");
147
                            new YAHOO.widget.Button("exportbutton");
147
                            new YAHOO.widget.Button("exportbutton");
148
                            new YAHOO.widget.Button("delbasketbutton");
148
                            new YAHOO.widget.Button("delbasketbutton");
149
                            new YAHOO.widget.Button("ediorderbutton");
149
                        }
150
                        }
150
                        //]]>
151
                        //]]>
151
                    </script>
152
                    </script>
Lines 160-165 Link Here
160
                        <li><a href="[% script_name %]?op=close&amp;basketno=[% basketno %]&amp;booksellerid=[% booksellerid %]" class="button" id="closebutton">Close this basket</a></li>
161
                        <li><a href="[% script_name %]?op=close&amp;basketno=[% basketno %]&amp;booksellerid=[% booksellerid %]" class="button" id="closebutton">Close this basket</a></li>
161
                    [% END %]
162
                    [% END %]
162
                        <li><a href="[% script_name %]?op=export&amp;basketno=[% basketno %]&amp;booksellerid=[% booksellerid %]" class="button" id="exportbutton">Export this basket as CSV</a></li>
163
                        <li><a href="[% script_name %]?op=export&amp;basketno=[% basketno %]&amp;booksellerid=[% booksellerid %]" class="button" id="exportbutton">Export this basket as CSV</a></li>
164
                    [% IF ediaccount %]
165
                        <li><a href="[% script_name %]?op=ediorder&amp;basketno=[% basketno %]&amp;booksellerid=[% booksellerid %]" class="button" id="ediorderbutton">EDIfact order</a></li>
166
                    [% END %]
163
                    </ul>
167
                    </ul>
164
168
165
                </div>
169
                </div>
Lines 187-193 Link Here
187
                [% END %]
191
                [% END %]
188
            [% END %]
192
            [% END %]
189
            [% END %]
193
            [% END %]
190
194
	[% IF ( edifile ) %]
195
	<div id="edifile" class="dialog alert">EDIfact order created and will be sent overnight. Filename: <strong>[% edifile %]</strong> - <a href="/cgi-bin/koha/acqui/basket.pl?op=edisend&basketno=[% basketno %]&booksellerid=[% booksellerid %]">Send this order now?</a></div>
196
	[% END %]
197
	[% IF ( edisend ) %]
198
	<div id="edisend" class="dialog alert"><strong>[% edisend %]</strong></div>
199
	[% END %]
191
    [% IF ( NO_BOOKSELLER ) %]
200
    [% IF ( NO_BOOKSELLER ) %]
192
    <h2>Vendor not found</h2>
201
    <h2>Vendor not found</h2>
193
    [% ELSE %]
202
    [% ELSE %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt (+2 lines)
Lines 107-112 Link Here
107
	<dd>Define which servers to query for MARC data in the integrated Z39.50 client.</dd>
107
	<dd>Define which servers to query for MARC data in the integrated Z39.50 client.</dd>
108
    <dt><a href="/cgi-bin/koha/admin/didyoumean.pl">Did you mean?</a></dt>
108
    <dt><a href="/cgi-bin/koha/admin/didyoumean.pl">Did you mean?</a></dt>
109
    <dd>Choose which plugins to use to suggest searches to patrons and staff.</dd>
109
    <dd>Choose which plugins to use to suggest searches to patrons and staff.</dd>
110
	<dt><a href="/cgi-bin/koha/admin/edi-accounts.pl">EDI Accounts</a></dt>
111
	<dd>Manage vendor EDI accounts for import/export</dd>
110
</dl>
112
</dl>
111
</div>
113
</div>
112
114
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-accounts.tt (+46 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Administration - EDI Accounts</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
5
</head>
6
<body>
7
[% INCLUDE 'header.inc' %]
8
[% INCLUDE 'cat-search.inc' %]
9
10
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; <a href="/cgi-bin/koha/admin/edi-accounts.pl">EDI Accounts</a></div>
11
12
<div id="doc3" class="yui-t2">
13
    <div id="bd">
14
        <div id="yui-main">
15
            <div class="yui-b"
16
				<h1>Vendor EDI Accounts</h1>
17
				[% IF ( ediaccounts ) %]
18
                <div id="ediaccounts" class="rows">
19
                    [% IF ( opdelsubmit ) %]
20
                    <div class="dialog alert">The account was successfully deleted</div>
21
                    [% END %]
22
                    [% IF ( opaddsubmit ) %]
23
                    <div class="dialog alert">The account was successfully added</div>
24
                    [% END %]
25
                    [% IF ( opeditsubmit ) %]
26
                    <div class="dialog alert">The account was successfully updated</div>
27
                    [% END %]
28
                        <div><ul class="toolbar"><li><span class="yui-button yui-link-button"><span class="first-child"><a href="/cgi-bin/koha/admin/edi-edit.pl?op=add">Add a new account</a></span></span></li></ul></div>
29
                        <table border="0" width="100%" cellpadding="3" cellspacing="0">
30
                        <th><strong>ID</strong></th><th><strong>Vendor</strong></th><th><strong>Description</strong></th><th><strong>Last activity</strong></th><th><strong>Actions</strong></th></tr>
31
                        [% FOREACH account IN ediaccounts %]
32
                            <tr><td>[% account.id %]</td><td><a href="/cgi-bin/koha/acqui/supplier.pl?supplierid=[% account.providerid %]">[% account.vendor %]</a></td><td>[% account.description %]</td><td>[% account.last_activity %]</td><td align="center"><a href="/cgi-bin/koha/admin/edi-edit.pl?op=edit&id=[% account.id %]&providerid=[% account.providerid %]">Edit</a> | <a href="/cgi-bin/koha/admin/edi-edit.pl?op=del&id=[% account.id %]">Delete</a></td></tr>
33
                        [% END %]
34
                        </table>
35
                </div>
36
                [% ELSE %]
37
                <p>You currently do not have any Vendor EDI Accounts. To add a new account <a href="/cgi-bin/koha/admin/edi-edit.pl?op=add">click here</a>.</p>
38
                [% END %]
39
            </div>
40
        </div>
41
        <div class="yui-b">
42
            [% INCLUDE 'admin-menu.inc' %]
43
        </div>
44
    </div>
45
</div>
46
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/edi-edit.tt (+102 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Administration - EDI Accounts</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
<script type="text/javascript" language="javascript">
5
$(document).ready(function() {
6
	$('#failcheck').hide();
7
});
8
function check_form_edi()
9
{
10
    if ($('#provider').val()!="" && $('#description').val()!="" && $('#host').val()!="")
11
    {
12
        $('#edi_form').submit();
13
    }
14
    else
15
    {
16
        $('#failcheck').show('fast');
17
    }
18
19
}
20
function deleteInstance()
21
{
22
    window.location="/cgi-bin/koha/members/houseboundinstances.pl?op=delsubmit&borrowernumber=[% borrowernumber %]&instanceid=[% delinstanceid %]&hbnumber=[% hbnumber %]";
23
}
24
function cancelInstance()
25
{
26
    window.location="/cgi-bin/koha/members/housebound.pl?borrowernumber=[% borrowernumber %]";
27
}
28
</script>
29
[% INCLUDE 'calendar.inc' %]
30
</head>
31
<body>
32
[% INCLUDE 'header.inc' %]
33
[% INCLUDE 'cat-search.inc' %]
34
35
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; <a href="/cgi-bin/koha/admin/edi-accounts.pl">EDI Accounts</a></div>
36
<div id="doc3" class="yui-t2">
37
    <div id="bd">
38
        <div id="yui-main">
39
            <div class="yui-b">
40
                <h1>Vendor EDI Accounts</h1>
41
                <div id="failcheck" class="dialog alert">You must complete all required fields</div>
42
                <form name="form" id="edi_form" method="post" action="/cgi-bin/koha/admin/edi-accounts.pl">
43
                    <input type="hidden" name="op" value="[% opeditsubmit %][% opaddsubmit %][% opdelsubmit %]" />
44
45
                    <input type="hidden" name="editid" value="[% editid %]" />
46
                [% IF opdel %]
47
                    <p>Are you sure you want to delete this account?</p>
48
                    <p><a href="/cgi-bin/koha/admin/edi-accounts.pl?id=[% id %]&op=delsubmit">YES</a> | <a href="/cgi-bin/koha/admin/edi-accounts.pl">NO</a></p>
49
                [% ELSE %]
50
                <fieldset class="rows" id="edi_details">
51
                    <legend>EDI Account details</legend>
52
                    <ol>
53
                        <li>
54
                            <label for="provider" class="required">Vendor:*</label>
55
                            <select id="provider" name="provider">
56
                                <option value="">Select a vendor</option>
57
                                [% FOREACH vendor IN vendorlist %]
58
                                    <option value="[% vendor.id %]" [% vendor.selected %]>[% vendor.name %]</option>
59
                                [% END %]
60
                            </select>
61
                        </li>
62
                        <li>
63
                            <label for="description" class="required">Description:* </label>
64
                            <input type="text" id="description" name="description" size="40" value="[% description %]" />
65
                        </li>
66
                        <li>
67
                            <label for="host" class="required">Server hostname:*</label>
68
                            <input type="text" id="host" name="host" size="40" value="[% host %]" />
69
                        </li>
70
                        <li>
71
                            <label for="user">Server username:</label>
72
                            <input type="text" id="user" name="user" size="40" value="[% user %]" />
73
                        </li>
74
                        <li>
75
                            <label for="pass">Server password:</label>
76
                            <input type="text" id="pass" name="pass" size="40" value="[% pass %]" />
77
                        </li>
78
                        <li>
79
                            <label for="in_dir">Server remote directory:</label>
80
                            <input type="text" id="in_dir" name="in_dir" size="40" value="[% in_dir %]" />
81
                        </li>
82
                        <li>
83
                            <label for="san">Vendor SAN:</label>
84
                            <input type="text" id="san" name="san" size="40" value="[% san %]" />
85
                        </li>
86
                    </ol>
87
                </fieldset>
88
                <fieldset class="action">
89
                    <input type="submit" value="Save" onclick="check_form_edi(); return false; " name="save">
90
                    <a class="cancel" href="/cgi-bin/koha/admin/edi-accounts.pl">Cancel</a>
91
                </fieldset>
92
                [% END %]
93
                </form>
94
95
            </div>
96
        </div>
97
        <div class="yui-b">
98
            [% INCLUDE 'admin-menu.inc' %]
99
        </div>
100
    </div>
101
</div>
102
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/edi.tt (+63 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Tools &rsaquo; EDIfact messages</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
<script type="text/javascript" language="javascript">
5
function check_sent(status,key,basketno,providerid)
6
{
7
	if (status == 'Failed' && basketno !=0)
8
	{
9
		document.write(' - (<a href="/cgi-bin/koha/acqui/basket.pl?op=edisend&basketno='+basketno+'&booksellerid='+providerid+'">Re-send</a>)');
10
	}
11
}
12
</script>
13
</head>
14
<body>
15
[% INCLUDE 'header.inc' %]
16
[% INCLUDE 'cat-search.inc' %]
17
18
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo; EDIfact messages</div>
19
20
<div id="doc3" class="yui-t2">
21
    <div id="bd">
22
        <div id="yui-main">
23
            <div class="yui-b"
24
         <h1>EDIfact messages</h1>
25
         [% IF messagelist %]
26
                <div id="messagelist" class="rows">
27
                    [% IF opdelsubmit %]
28
                    <div class="dialog alert">The account was successfully deleted</div>
29
                    [% END %]
30
                    [% IF opaddsubmit %]
31
                    <div class="dialog alert">The account was successfully added</div>
32
                    [% END %]
33
                    [% IF opeditsubmit %]
34
                    <div class="dialog alert">The account was successfully updated</div>
35
                    [% END %]
36
                        <table border="0" width="100%" cellpadding="3" cellspacing="0">
37
                        <th><strong>Date</strong></th><th><strong>Message type</strong></th><th><strong>Provider</strong></th><th><strong>Status</strong></th><th>Basket</th>
38
                        [% FOREACH message IN messagelist %]
39
                        <tr>
40
                            <td>[% message.date_sent %]</td>
41
                            <td>[% message.message_type %]</td>
42
                            <td><a href="/cgi-bin/koha/acqui/supplier.pl?supplierid=[% message.providerid %]">[% message.providername %]</a></td>
43
                            <td>[% message.status %]<script type="text/javascript" language="javascript">check_sent('[% message.status %]',[% message.id %],[% message.basketno %],[% message.providerid %]);</script></td>
44
                            <td>
45
                            [% IF message.basketno %]
46
                            <a href="/cgi-bin/koha/acqui/basket.pl?basketno=[% message.basketno %]">View basket</a>
47
                            [% END %]
48
                            </td></tr>
49
                        [% END %]
50
                        </table>
51
                </div>
52
53
                [% ELSE %]
54
                <p>There are currently no EDIfact messages to display.</p>
55
                [% END %]
56
            </div>
57
        </div>
58
        <div class="yui-b">
59
            [% INCLUDE 'tools-menu.inc' %]
60
        </div>
61
    </div>
62
</div>
63
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt (+5 lines)
Lines 97-102 Link Here
97
    <dd>Quote editor for Quote-of-the-day feature in OPAC</dd>
97
    <dd>Quote editor for Quote-of-the-day feature in OPAC</dd>
98
    [% END %]
98
    [% END %]
99
99
100
    [% IF ( CAN_user_tools_edi_manage ) %]
101
    <dt><a href="/cgi-bin/koha/tools/edi.pl">EDIfact messages</a></dt>
102
    <dd>Manage EDIfact transmissions</dd>
103
    [% END %]
104
100
</dl>
105
</dl>
101
</div>
106
</div>
102
<div class="yui-u">
107
<div class="yui-u">
(-)a/misc/cronjobs/clean_edifiles.pl (+43 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011 Mark Gavillet & PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use C4::Context;
23
my $edidir = C4::Context->config('intranetdir');
24
25
$edidir .= '/misc/edi_files';
26
opendir( my $dh, $edidir );
27
my @files = readdir($dh);
28
close $dh;
29
30
foreach my $file (@files) {
31
    my $now  = time;
32
    my @stat = stat("$edidir/$file");
33
    if (
34
        $stat[9] < ( $now - 2592000 )
35
        && (   ( index lc($file), '.ceq' ) > -1
36
            || ( index lc($file), '.cep' ) > -1 )
37
      )
38
    {
39
        print "Deleting file $edidir/$file...";
40
        unlink("$edidir/$file");
41
        print "Done.\n";
42
    }
43
}
(-)a/misc/cronjobs/edifact_order_ftp_transfer.pl (+127 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011,2012 Mark Gavillet & PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use C4::Context;
23
use C4::EDI qw ( GetEDIFTPAccounts ParseEDIQuote LogEDITransaction);
24
use Net::FTP;
25
26
my $ftpaccounts = GetEDIFTPAccounts;
27
28
my @errors;
29
my @putdirlist;
30
my $newerr;
31
my @files;
32
my $putdir = C4::Context->config('intranetdir');
33
$putdir .= '/misc/edi_files/';
34
my $ediparse;
35
opendir( my $dh, $putdir );
36
@putdirlist = readdir $dh;
37
closedir $dh;
38
39
foreach my $accounts (@$ftpaccounts) {
40
    my $ftp = Net::FTP->new( $accounts->{host}, Timeout => 10, Passive => 1 )
41
      or $newerr = 1;
42
    $ftp->binary();
43
    push @errors, "Can't ftp to $accounts->{host}: $!\n" if $newerr;
44
    myerr() if $newerr;
45
    if ( !$newerr ) {
46
        $newerr = 0;
47
        print "Connected to $accounts->{host}\n";
48
49
        $ftp->login( "$accounts->{username}", "$accounts->{password}" )
50
          or $newerr = 1;
51
        print "Getting file list\n";
52
        push @errors, "Can't login to $accounts->{host}: $!\n" if $newerr;
53
        $ftp->quit if $newerr;
54
        myerr() if $newerr;
55
        if ( !$newerr ) {
56
            print "Logged in\n";
57
            $ftp->cwd( $accounts->{in_dir} ) or $newerr = 1;
58
            push @errors, "Can't cd in server $accounts->{host} $!\n"
59
              if $newerr;
60
            myerr() if $newerr;
61
            $ftp->quit if $newerr;
62
63
            @files = $ftp->ls or $newerr = 1;
64
            push @errors,
65
              "Can't get file list from server $accounts->{host} $!\n"
66
              if $newerr;
67
            myerr() if $newerr;
68
            if ( !$newerr ) {
69
                print "Got  file list\n";
70
                foreach my $file (@files) {
71
                    if ( $file =~ m/\.ceq/i ) {
72
                        my $match;
73
                        foreach my $f (@putdirlist) {
74
                            if ( $f eq $file ) {
75
                                $match = 1;
76
                                last;
77
                            }
78
                        }
79
                        if ( $match != 1 ) {
80
                            chdir $putdir;
81
                            $ftp->get($file) or $newerr = 1;
82
                            push @errors,
83
"Can't transfer file ($file) from $accounts->{host} $!\n"
84
                              if $newerr;
85
                            $ftp->quit if $newerr;
86
                            myerr() if $newerr;
87
                            if ( !$newerr ) {
88
                                $ediparse =
89
                                  ParseEDIQuote( $file, $accounts->{provider} );
90
                            }
91
                            if ( $ediparse == 1 ) {
92
                                my $qext    = '.ceq';
93
                                my $rext    = '.eeq';
94
                                my $renamed = lc $file;
95
                                $renamed =~ s/$qext/$rext/g;
96
                                $ftp->rename( $file, $renamed );
97
                            }
98
                        }
99
                    }
100
                }
101
            }
102
        }
103
        if ( !$newerr ) {
104
            LogEDITransaction( $accounts->{id} );
105
        }
106
        $ftp->quit;
107
    }
108
    $newerr = 0;
109
}
110
111
print "\n@errors\n";
112
113
if (@errors) {
114
    my $logfile = C4::Context->config('intranetdir');
115
    $logfile .= '/misc/edi_files/edi_ftp_error.log';
116
    open my $fh, '>>', $logfile;
117
    my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
118
    printf $fh "%4d-%02d-%02d %02d:%02d:%02d\n-----\n", $year + 1900,
119
      $mon + 1, $mday, $hour, $min, $sec;
120
    print $fh "@errors\n";
121
    close $fh;
122
}
123
124
sub myerr {
125
    print 'Error: ', @errors;
126
    return;
127
}
(-)a/misc/cronjobs/send_queued_edi_orders.pl (+26 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011 Mark Gavillet & PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use C4::Context;
23
use C4::EDI qw( SendQueuedEDIOrders );
24
25
26
SendQueuedEDIOrders();
(-)a/misc/edi_files/README.txt (+3 lines)
Line 0 Link Here
1
This is a readme file but is secretly just a placeholder for the edi_files directory.
2
3
--Elliott Davis
(-)a/t/Calendar.t (-1 lines)
Lines 36-42 $module_context->mock( Link Here
36
        return 'Calendar';
36
        return 'Calendar';
37
    }
37
    }
38
);
38
);
39
40
SKIP: {
39
SKIP: {
41
40
42
skip "DBD::Mock is too old", 33
41
skip "DBD::Mock is too old", 33
(-)a/t/EDI.t (+85 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
use strict;
4
use warnings;
5
use Test::More qw/no_plan/;
6
use Test::MockModule;
7
use DBD::Mock;
8
9
my $module_context = new Test::MockModule('C4::Context');
10
my $module_budgets = new Test::MockModule("C4::Budgets");
11
12
$module_context->mock(
13
    '_new_dbh',
14
    sub {
15
        my $dbh = DBI->connect( 'DBI:Mock:', '', '' )
16
	    || die "Cannot create handle: $DBI::errstr\n";
17
        return $dbh;
18
    }
19
    );
20
21
my $dbh = C4::Context->dbh();
22
23
$module_context->mock("EDIfactEAN",sub{ return 1; });
24
$module_budgets->mock('GetCurrency',sub{ return {currency => "USD"}; });
25
26
use_ok('C4::EDI');
27
 SKIP: {
28
     skip "DBD::Mock is too old", 33
29
	 unless $DBD::Mock::VERSION >= 1.45;
30
     
31
     $dbh->{mock_session} = DBD::Mock::Session->new('EDI_session' => (
32
							{ #GetVendorList
33
							    statement => "select id, name from aqbooksellers order by name asc",
34
							    results => [
35
								["id","name"],
36
								[1,"Amazon"],
37
								]
38
							},
39
							{ #GetEDIAccounts
40
							    statement => "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",
41
							    results => [
42
								["vendor_edi_accounts.id", "providerid", "vendor", "vendor_edi_accounts.description", "vendor_edi_accounts.last_activity"],
43
								[1,1,"Amazon", "Online Bookseller","2013-01-01 00:00:00"],
44
								]
45
							},
46
							{ #GetEDIAccounts
47
							    statement => "select san from vendor_edi_accounts where provider=?",
48
							    results => [
49
								["san"],
50
								[1],
51
								]
52
							},
53
							{ 
54
							    statement => "select message_type from edifact_messages where basketno=?",
55
							    results => [
56
								["message_type"],
57
								["QUOTE"],
58
								]
59
							}
60
						    )
61
	 );    
62
     cmp_ok(C4::EDI->GetVendorList()->[0]->{name}, 'eq', 'Amazon');
63
     cmp_ok(C4::EDI->GetEDIAccounts->[0]->{vendor}, 'eq', 'Amazon');
64
65
my $module_acquisition = new Test::MockModule("C4::Acquisition");
66
$module_acquisition->mock('GetOrderItemInfo',sub{ return ("MPL","npl.lgf","BOOK","1234","Emergency"); });
67
$module_acquisition->mock('GetOrders',sub{
68
    return ({title => "test",
69
	     author => "test",
70
	     publishercode => '1',
71
	     isbn => '1234567890',
72
	     publicationyear => "1996",
73
	     quantity => '1',
74
	     ordernumber => '35',
75
	     notes => "test_notes",
76
	    });
77
78
});
79
80
my ($basketno, $booksellerid) = 1;
81
(-e C4::EDI->CreateEDIOrder($basketno,$booksellerid)) ? 
82
    pass("Create EDI File!") : 
83
    fail("Create EDI file!");
84
85
} # End Skip Block
(-)a/tools/edi.pl (-1 / +43 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# Copyright 2011 Mark Gavillet & PTFS Europe Ltd
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
use CGI;
23
use C4::Auth;
24
use C4::Output;
25
use C4::EDI qw( GetEDIfactMessageList);
26
27
my $input = CGI->new();
28
29
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
30
    {
31
        template_name   => 'tools/edi.tmpl',
32
        query           => $input,
33
        type            => 'intranet',
34
        authnotrequired => 0,
35
        flagsrequired   => { borrowers => 1 },
36
    }
37
);
38
39
my $messagelist = GetEDIfactMessageList();
40
41
$template->param( messagelist => $messagelist );
42
43
output_html_with_http_headers $input, $cookie, $template->output;

Return to bug 7736