2 # ---------------------------------------------------------------
3 # Copyright (C) 2010 Equinox Software, Inc
4 # Author: Joe Atzberger <jatzberger@esilibrary.com>
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 # ---------------------------------------------------------------
23 use OpenILS::Utils::Cronscript;
24 use OpenILS::Utils::Fieldmapper;
25 use OpenILS::Application::AppUtils;
26 use OpenILS::Application::Acq::EDI;
27 use OpenSRF::Utils::Logger q/$logger/;
36 'max-batch-size=i' => -1,
38 # if true, print final EDI to STDOUT, send nothign to the vendor, write nothing to the DB
42 my $cs = OpenILS::Utils::Cronscript->new(\%defaults);
44 my $opts = $cs->MyGetOptions();
45 my $e = $cs->editor() or die "Failed to get new CStoreEditor";
46 my $hook = 'acqpo.activated';
47 my $defs = $e->search_action_trigger_event_definition({
49 reactor => 'GeneratePurchaseOrderJEDI',
53 $opts->{verbose} = 0 if $opts->{quiet};
55 print "FTP_PASSIVE is ", ($ENV{FTP_PASSIVE} ? "ON" : "OFF"), "\n";
57 print "\nHook '$hook' is used in ", scalar(@$defs), " event definition(s):\n";
59 $Data::Dumper::Indent = 1;
60 my $remaining = $opts->{'max-batch-size'};
62 # FIXME: this is the disclusion subquery. It discludes any PO that has
63 # a non-retry edi_message linked to it. But that means that if there are
64 # mutliple EDI messages (say, some failed translation) and one marked retry,
65 # the PO is still discluded! Perhaps there should never be multiple messages,
66 # but that makes testing much trickier (and is not DB-enforced).
68 # One approach might be to supplementally query for any "retry" messages that
69 # are on active providers (and deduplicate).
72 select => { acqedim => ['purchase_order'] },
75 message_type => 'ORDERS',
76 status => {'!=' => 'retry' },
77 purchase_order => {'!=' => undef }
81 foreach my $def (@$defs) {
82 last if $remaining == 0;
83 printf "%3s - '%s'\n", $def->id, $def->name;
85 # give me all completed JEDI events that link to purchase_orders
86 # that have no delivery attempts or are in the retry state
89 select => {atev => ['id']},
92 event_def => $def->id,
98 order_by => {atev => ['add_time']}
101 $query->{limit} = $remaining if $remaining > 0;
103 if ($opts->{verbose}) {
104 # $subq->{'select'}->{'acqedim'} = ['id', 'purchase_order', 'message_type', 'status'];
105 my $excluded = $e->json_query($subq);
106 print "Excluded: ", scalar(@$excluded), " purchase order(s):\n";
108 print map {sprintf "%7d%s", $_, (++$z % 5) ? '' : "\n"} sort {$a <=> $b} map {$_->{purchase_order}} @$excluded;
112 my $events = $e->json_query($query);
115 print STDERR "error querying JEDI events for event definition ", $def->id, "\n";
116 $logger->error("error querying JEDI events for event definition ". $def->id);
120 $remaining -= scalar(@$events);
122 print "Event definition ", $def->id, " has ", scalar(@$events), " (completed) event(s)\n";
125 my $event = $e->retrieve_action_trigger_event([
127 {flesh => 1, flesh_fields => {atev => ['template_output']}}
131 my $target = $e->retrieve_acq_purchase_order([ # instead we retrieve it separately
135 acqpo => ['provider'],
136 acqpro => ['edi_default'],
141 # this may be a retry attempt. if so, reuse the original edi_message
142 my $message = $e->search_acq_edi_message({
143 purchase_order => $target->id,
144 message_type => 'ORDERS',
149 $message = Fieldmapper::acq::edi_message->new;
150 $message->create_time('NOW'); # will need this later when we try to update from the object
151 $message->purchase_order($target->id);
152 $message->message_type('ORDERS');
156 my $logstr = sprintf "provider %s (%s)", $target->provider->id, $target->provider->name;
157 unless ($target->provider->edi_default and $message->account($target->provider->edi_default->id)) {
158 printf STDERR "ERROR: No edi_default account found for $logstr. File will not be sent!\n";
161 $message->jedi($event->template_output()->data);
163 print "\ntarget->provider->edi_default->id: ", $target->provider->edi_default->id, "\n";
164 my $logstr2 = sprintf "event %s, PO %s, template_output %s", $_->{id}, $message->purchase_order, $event->template_output->id;
166 print "Test mode, skipping translation/send\n";
170 printf "\nNow calling attempt_translation for $logstr2\n\n";
172 unless (OpenILS::Application::Acq::EDI->attempt_translation($message, 1)) {
173 print STDERR "ERROR: attempt_translation failed for $logstr2\n";
175 # The premise here is that if the translator failed, it is better to try again later from a "fresh" fetched file
176 # than to add a cascade of failing inscrutable copies of the same message(s) to our DB.
179 if ($opts->{'debug-only'}) {
180 print OpenILS::Application::Acq::EDI->attempt_translation($message, 1)->edi . "\n";
181 print "\ndebug-only => skipping FTP\n";
185 print "Writing new message + translation to DB for $logstr2\n";
188 if($message->isnew) {
189 unless($e->create_acq_edi_message($message)) {
190 $logger->error("Error creating acq.edi_message for $logstr2: ".$e->die_event);
194 unless($e->update_acq_edi_message($message)) {
195 $logger->error("Error updating acq.edi_message for $logstr2: ".$e->die_event);
201 print "Calling send_core(...) for message (", $message->id, ")\n";
202 my $res = OpenILS::Application::Acq::EDI->send_core($target->provider->edi_default, [$message->id]);
204 my $message_out = shift @$res;
205 print "\tmessage ", $message->id, " status: ", $message_out->status, "\n";
207 print STDERR "ERROR: send_core failed for message ", $message->id, "\n";
218 edi_pusher.pl - A script for generating and sending EDI files to remote accounts.
222 This script is expected to be run via crontab, for the purpose of retrieving vendor EDI files.
226 --max-batch-size=i Limit the processing to a set number of events.
234 B<FTP_PASSIVE=1> is recommended. Depending on your vendors' and your own network environments, you may want to set/export
235 the environmental variable FTP_PASSIVE like:
239 FTP_PASSIVE=1 Open-ILS/src/support-scripts/edi_pusher.pl
243 OpenILS::Utils::Cronscript
248 Joe Atzberger <jatzberger@esilibrary.com>