use File::Temp;
use Getopt::Long qw(:DEFAULT GetOptionsFromArray);
use Pod::Usage;
+use File::Spec;
use OpenSRF::Utils::Logger qw/$logger/;
use OpenSRF::AppSession;
use OpenSRF::Utils::Cache;
use OpenILS::Utils::Cronscript;
use OpenILS::Utils::CStoreEditor;
+use OpenILS::Utils::Fieldmapper;
require 'oils_header.pl';
use vars qw/$apputils/;
my $acq_ses;
my $authtoken;
-
+my $conf;
+my $cache;
+my $editor;
+my $base_dir;
+my $share_dir;
+my $providers;
my $debug = 0;
my %defaults = (
print STDERR "\nERROR: password option required for session login\n\n";
}
-print Dumper($o) if $debug;
+$debug and print Dumper($o);
if ($debug) {
foreach my $ref (qw/osrf_config oils_username oils_password help debug/) {
my $file = shift;
my $args = shift;
- print "Pushing file '$file' to provider " . $args->{provider} . "\n";
+ $logger->info("acq-or: pushing file '$file' to provider " . $args->{provider});
# Cache the file name like Vandelay does. ACQ will
# read contents of the cache and then delete them.
my $key = $$ . time . rand();
$cache->put_cache("vandelay_import_spool_$key", {path => $file});
+ # some arguments are not optional
+ $args->{create_po} = 1;
+
+ # don't send our internal args to the service
+ my $local = delete $args->{_local};
+
my $req = $acq_ses->request(
'open-ils.acq.process_upload_records',
$authtoken,
while (my $resp = $req->recv(timeout => 600)) {
if(my $content = $resp->content) {
- print Dumper($content) if $debug;
+ $debug and print Dumper($content);
} else {
warn "Request returned no data: " . Dumper($resp) . "\n";
}
}
-}
+ # TODO: delete tmp queue?
+}
-open-ils.acq open-ils.acq.process_upload_records "ce5ab1499cf019c0b52bf9eab87335fc", "f15791c2bcea4296c0d2c955c5204125", {"picklist":null,"provider":"1","ordering_agency":"4","create_po":false,"activate_po":"on","vandelay":{"import_no_match":"on","auto_overlay_exact":"on","auto_overlay_1match":false,"auto_overlay_best_match":false,"match_quality_ratio":"0.0","queue_name":"acq.bt.2","create_assets":false,"match_set":"","bib_source":"","merge_profile":"1","fall_through_merge_profile":"","existing_queue":""}}
+sub org_from_sn {
+ my $sn = shift;
+ my $org = $editor->search_actor_org_unit({shortname => $sn})->[0];
+ if (!$org) {
+ warn "No such org unit in acq_order_reader config: '$sn'\n";
+ return undef;
+ }
+ return $org;
+}
sub args_from_provider_conf {
my $conf = shift;
+ my %args;
my $pcode = $conf->{code};
my $orgsn = $conf->{owner};
- my $org = $editor->search_actor_org_unit(shortname => $orgsn)->[0];
- if (!$org) {
- warn "No such org unit in acq_order_reader config: '$orgsn'\n";
- next;
- }
+ $debug and print "Extracting request args for provider $pcode at $orgsn\n";
+
+ my $org = org_from_sn($conf->{owner}) or return undef;
my $provider = $editor->search_acq_provider({
code => $pcode,
owner => $org->id
- });
+ })->[0];
if (!$provider) {
warn "No such provider in acq_order_reader config: '$pcode'\n";
- next;
+ return undef;
+ }
+
+ my $oa = org_from_sn($conf->{ordering_agency}) or return undef;
+
+ $args{provider} = $provider->id;
+ $args{ordering_agency} = $oa->id;
+ $args{activate_po} = ($conf->{activate_po} || '') =~ /true/i;
+
+ # vandelay import options
+ my $vconf = $conf->{vandelay} || {};
+ $args{vandelay} = {};
+
+ # value options
+ for my $opt (
+ qw/
+ match_quality_ratio
+ match_set
+ bib_source
+ merge_profile / ) {
+
+ $args{vandelay}->{$opt} = $vconf->{$opt}
}
+ # boolean options
+ for my $opt (
+ qw/
+ create_assets
+ import_no_match
+ auto_overlay_exact
+ auto_overlay_1match
+ auto_overlay_best_match/ ) {
+
+ $args{vandelay}->{$opt} = 1 if ($vconf->{$opt} || '') =~ /true/i;
+ }
+
+ if ($vconf->{queue}) {
+ $args{vandelay}->{queue_name} = $vconf->{queue};
+ $args{vandelay}->{existing_queue} = $vconf->{queue};
+
+ } else {
+
+ # create a temporary queue
+ $args{vandelay}->{queue_name} = sprintf("acq-order-reader-%s-%s-%s",
+ $org->shortname, $provider->code, $apputils->epoch2ISO8601(time));
+ }
+
+ $args{_local} = {
+ provider_code => $pcode, # good for debugging
+ dirname => File::Spec->catfile($base_dir, $conf->{subdir})
+ };
+
+ return \%args;
+}
+
+# returns the list of new order record files that
+# need to be processed for this vendor
+sub check_provider_files {
+ my $args = shift;
+ my $dirname = $args->{_local}->{dirname};
+ my $dh;
+ my @files;
+
+ $debug and print "Searching for new files at $dirname\n";
+
+ if ( !opendir($dh, $dirname) ) {
+ warn "Couldn't open dir '$dirname': $!";
+ return @files;
+ }
+
+ @files = readdir $dh;
+ # ignore '.', '..', and hidden files
+ @files = grep {$_ !~ /^\./} @files;
+
+ $logger->info("acq-or: found " . scalar(@files) . " ACQ order files at $dirname");
+
+ # return the file names w/ full path
+ return map {File::Spec->catfile($dirname, $_)} @files;
}
# -----------------------------------------------------
osrf_connect($osrf_config);
-my $conf = OpenSRF::Utils::SettingsClient->new;
-my $base_dir = $conf->config_value(acq_order_reader => 'base_dir');
-my $share_dir = $conf->config_value(acq_order_reader => 'shared_subdir');
-my $providers = $conf->config_value(acq_order_reader => 'provider');
+$conf = OpenSRF::Utils::SettingsClient->new;
+$cache = OpenSRF::Utils::Cache->new;
+$editor = OpenILS::Utils::CStoreEditor->new;
+$acq_ses = OpenSRF::AppSession->create('open-ils.acq');
-print Dumper($providers) if $debug;
+my $user = $editor->search_actor_user({usrname => $oils_username})->[0];
+if (!$user) {
+ warn "Invalid user: $oils_username\n";
+ exit;
+}
-$acq_ses = OpenSRF::AppSession->create('open-ils.acq');
-my $cache = OpenSRF::Utils::Cache->new;
-my $editor = OpenILS::Utils::CStoreEditor->new;
+# read configs
+$base_dir = $conf->config_value(acq_order_reader => 'base_dir');
+$share_dir = $conf->config_value(acq_order_reader => 'shared_subdir');
+$providers = $conf->config_value(acq_order_reader => 'provider');
+$providers = [$providers] unless ref $providers eq 'ARRAY';
+$debug and print Dumper($providers);
+
+# -----------------------------------------------------
# main loop
# for each provider directory, plus the shared directory, check
# to see if there are any files pending. For any files found, push
# them up to the ACQ service, then delete the file
-
while (1) {
-
new_auth_token();
+ my $processed = 0;
# explicit providers
for my $provider_conf (@$providers) {
my $args = args_from_provider_conf($provider_conf) or next;
my @files = check_provider_files($args);
- push_file_to_acq($_, $args) @files;
+ push_file_to_acq($_, $args) for @files;
+ $processed += scalar(@files);
}
# shared directory
+ # TODO
clear_auth_token();
- print "Sleeping for $poll_time seconds...\n" if $debug;
- sleep $poll_time;
+ $logger->info("acq-or: loop processed $processed files");
+ $debug and print "Sleeping for $poll_interval seconds...\n";
+ sleep $poll_interval;
}
warn "Exiting main acq_order_reader loop!\n";