acq order reader; continuing
authorBill Erickson <berick@esilibrary.com>
Mon, 23 Jul 2012 16:14:52 +0000 (12:14 -0400)
committerBill Erickson <berick@esilibrary.com>
Mon, 23 Jul 2012 16:14:52 +0000 (12:14 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/examples/opensrf.xml.example
Open-ILS/src/support-scripts/acq_order_reader.pl

index f1a4dab..05891ae 100644 (file)
@@ -282,16 +282,21 @@ vim:et:ts=4:sw=4:
             <!-- providers that don't provide a mechanism to inspect the file
                  have to push their files to provider-specific locations -->
             <provider>
-                <code>BAB</code>     <!-- acq.provider.code -->
-                <owner>CONS</owner>  <!-- actor.org_unit.shortname -->
-                <subdir>BAB</subdir> <!-- base_dir + subdir = full path -->
+                <code>BAB</code>     <!-- provider code -->
+                <owner>CONS</owner>  <!-- provider owner; org unit shortname -->
+                <subdir>CONS-BAB</subdir> <!-- base_dir + subdir = full path -->
+                <ordering_agency>BR1</ordering_agency> <!-- who gets/manages the order -->
+                <activate_po>false</activate_po> <!-- activate at upload? -->
+                <vandelay>
+                    <import_no_match>true</import_no_match>
+                </vandelay>
             </provider>
 
+            <!-- Add as needed...
             <provider>
-                <code>ABC</code>
-                <owner>BR1</owner>
-                <subdir>ABC</subdir>
             </provider>
+            -->
+
         </acq_order_reader>
 
 
index 70f93d3..0a24f2b 100755 (executable)
@@ -22,6 +22,7 @@ use Data::Dumper;
 use File::Temp;
 use Getopt::Long qw(:DEFAULT GetOptionsFromArray);
 use Pod::Usage;
+use File::Spec;
 
 use OpenSRF::Utils::Logger qw/$logger/;
 use OpenSRF::AppSession;
@@ -30,12 +31,18 @@ use OpenSRF::Utils::SettingsClient;
 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 = (
@@ -89,7 +96,7 @@ unless ($oils_password) {
     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/) {
@@ -120,7 +127,7 @@ sub push_file_to_acq {
     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.
@@ -128,6 +135,12 @@ sub push_file_to_acq {
     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,
@@ -137,38 +150,121 @@ sub push_file_to_acq {
 
     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;
 }
 
 # -----------------------------------------------------
@@ -177,40 +273,51 @@ sub args_from_provider_conf {
 
 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";