]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Vandelay.pm
Address long-standing typo: clense_ISO8601, matching change to OpenSRF-trunk.
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Vandelay.pm
1 package OpenILS::Application::Vandelay;
2 use strict; use warnings;
3 use OpenILS::Application;
4 use base qw/OpenILS::Application/;
5 use Unicode::Normalize;
6 use OpenSRF::EX qw/:try/;
7 use OpenSRF::AppSession;
8 use OpenSRF::Utils::SettingsClient;
9 use OpenSRF::Utils::Cache;
10 use OpenILS::Utils::Fieldmapper;
11 use OpenILS::Utils::CStoreEditor qw/:funcs/;
12 use MARC::Batch;
13 use MARC::Record;
14 use MARC::File::XML;
15 use OpenILS::Utils::Fieldmapper;
16 use Time::HiRes qw(time);
17 use OpenSRF::Utils::Logger qw/$logger/;
18 use MIME::Base64;
19 use OpenILS::Const qw/:const/;
20 use OpenILS::Application::AppUtils;
21 use OpenILS::Application::Cat::BibCommon;
22 use OpenILS::Application::Cat::AuthCommon;
23 use OpenILS::Application::Cat::AssetCommon;
24 my $U = 'OpenILS::Application::AppUtils';
25
26 sub initialize {}
27 sub child_init {}
28
29 # --------------------------------------------------------------------------------
30 # Biblio ingest
31
32 sub create_bib_queue {
33         my $self = shift;
34         my $client = shift;
35         my $auth = shift;
36         my $name = shift;
37         my $owner = shift;
38         my $type = shift;
39
40         my $e = new_editor(authtoken => $auth, xact => 1);
41
42         return $e->die_event unless $e->checkauth;
43         return $e->die_event unless $e->allowed('CREATE_BIB_IMPORT_QUEUE');
44     $owner ||= $e->requestor->id;
45
46     return OpenILS::Event->new('BIB_QUEUE_EXISTS') 
47         if $e->search_vandelay_bib_queue(
48             {name => $name, owner => $owner, queue_type => $type})->[0];
49
50         my $queue = new Fieldmapper::vandelay::bib_queue();
51         $queue->name( $name );
52         $queue->owner( $owner );
53         $queue->queue_type( $type ) if ($type);
54
55         my $new_q = $e->create_vandelay_bib_queue( $queue );
56         return $e->die_event unless ($new_q);
57         $e->commit;
58
59     return $new_q;
60 }
61 __PACKAGE__->register_method(  
62         api_name        => "open-ils.vandelay.bib_queue.create",
63         method          => "create_bib_queue",
64         api_level       => 1,
65         argc            => 3,
66 );                      
67
68
69 sub create_auth_queue {
70         my $self = shift;
71         my $client = shift;
72         my $auth = shift;
73         my $name = shift;
74         my $owner = shift;
75         my $type = shift;
76
77         my $e = new_editor(authtoken => $auth, xact => 1);
78
79         return $e->die_event unless $e->checkauth;
80         return $e->die_event unless $e->allowed('CREATE_AUTHORITY_IMPORT_QUEUE');
81     $owner ||= $e->requestor->id;
82
83     return OpenILS::Event->new('AUTH_QUEUE_EXISTS') 
84         if $e->search_vandelay_bib_queue(
85             {name => $name, owner => $owner, queue_type => $type})->[0];
86
87         my $queue = new Fieldmapper::vandelay::authority_queue();
88         $queue->name( $name );
89         $queue->owner( $owner );
90         $queue->queue_type( $type ) if ($type);
91
92         my $new_q = $e->create_vandelay_authority_queue( $queue );
93         $e->die_event unless ($new_q);
94         $e->commit;
95
96     return $new_q;
97 }
98 __PACKAGE__->register_method(  
99         api_name        => "open-ils.vandelay.authority_queue.create",
100         method          => "create_auth_queue",
101         api_level       => 1,
102         argc            => 3,
103 );                      
104
105 sub add_record_to_bib_queue {
106         my $self = shift;
107         my $client = shift;
108         my $auth = shift;
109         my $queue = shift;
110         my $marc = shift;
111         my $purpose = shift;
112     my $bib_source = shift;
113
114         my $e = new_editor(authtoken => $auth, xact => 1);
115
116         $queue = $e->retrieve_vandelay_bib_queue($queue);
117
118         return $e->die_event unless $e->checkauth;
119         return $e->die_event unless
120                 ($e->allowed('CREATE_BIB_IMPORT_QUEUE', undef, $queue) ||
121                  $e->allowed('CREATE_BIB_IMPORT_QUEUE'));
122
123         my $new_rec = _add_bib_rec($e, $marc, $queue->id, $purpose, $bib_source);
124
125         return $e->die_event unless ($new_rec);
126         $e->commit;
127     return $new_rec;
128 }
129 __PACKAGE__->register_method(  
130         api_name        => "open-ils.vandelay.queued_bib_record.create",
131         method          => "add_record_to_bib_queue",
132         api_level       => 1,
133         argc            => 3,
134 );                      
135
136 sub _add_bib_rec {
137         my $e = shift;
138         my $marc = shift;
139         my $queue = shift;
140         my $purpose = shift;
141     my $bib_source = shift;
142
143         my $rec = new Fieldmapper::vandelay::queued_bib_record();
144         $rec->marc( $marc );
145         $rec->queue( $queue );
146         $rec->purpose( $purpose ) if ($purpose);
147     $rec->bib_source($bib_source);
148
149         return $e->create_vandelay_queued_bib_record( $rec );
150 }
151
152 sub add_record_to_authority_queue {
153         my $self = shift;
154         my $client = shift;
155         my $auth = shift;
156         my $queue = shift;
157         my $marc = shift;
158         my $purpose = shift;
159
160         my $e = new_editor(authtoken => $auth, xact => 1);
161
162         $queue = $e->retrieve_vandelay_authority_queue($queue);
163
164         return $e->die_event unless $e->checkauth;
165         return $e->die_event unless
166                 ($e->allowed('CREATE_AUTHORITY_IMPORT_QUEUE', undef, $queue) ||
167                  $e->allowed('CREATE_AUTHORITY_IMPORT_QUEUE'));
168
169         my $new_rec = _add_auth_rec($e, $marc, $queue->id, $purpose);
170
171         return $e->die_event unless ($new_rec);
172         $e->commit;
173     return $new_rec;
174 }
175 __PACKAGE__->register_method(
176         api_name        => "open-ils.vandelay.queued_authority_record.create",
177         method          => "add_record_to_authority_queue",
178         api_level       => 1,
179         argc            => 3,
180 );
181
182 sub _add_auth_rec {
183         my $e = shift;
184         my $marc = shift;
185         my $queue = shift;
186     my $purpose = shift;
187
188         my $rec = new Fieldmapper::vandelay::queued_authority_record();
189         $rec->marc( $marc );
190         $rec->queue( $queue );
191         $rec->purpose( $purpose ) if ($purpose);
192
193         return $e->create_vandelay_queued_authority_record( $rec );
194 }
195
196 sub process_spool {
197         my $self = shift;
198         my $client = shift;
199         my $auth = shift;
200         my $fingerprint = shift;
201         my $queue_id = shift;
202
203         my $e = new_editor(authtoken => $auth, xact => 1);
204     return $e->die_event unless $e->checkauth;
205
206     my $queue;
207     my $type = $self->{record_type};
208
209     if($type eq 'bib') {
210         $queue = $e->retrieve_vandelay_bib_queue($queue_id) or return $e->die_event;
211     } else {
212         $queue = $e->retrieve_vandelay_authority_queue($queue_id) or return $e->die_event;
213     }
214
215     my $evt = check_queue_perms($e, $type, $queue);
216     return $evt if $evt;
217
218         my $method = "open-ils.vandelay.queued_${type}_record.create";
219         $method = $self->method_lookup( $method );
220
221     my $cache = new OpenSRF::Utils::Cache();
222
223     my $data = $cache->get_cache('vandelay_import_spool_' . $fingerprint);
224         my $purpose = $data->{purpose};
225     my $filename = $data->{path};
226     my $bib_source = $data->{bib_source};
227
228     unless(-r $filename) {
229         $logger->error("unable to read MARC file $filename");
230         return -1; # make this an event XXX
231     }
232
233     $logger->info("vandelay spooling $fingerprint purpose=$purpose file=$filename");
234
235     my $marctype = 'USMARC'; 
236
237     open F, $filename;
238     $marctype = 'XML' if (getc(F) =~ /^\D/o);
239     close F;
240
241         my $batch = new MARC::Batch ($marctype, $filename);
242         $batch->strict_off;
243
244         my $count = 0;
245         my $r = -1;
246         while (try { $r = $batch->next } otherwise { $r = -1 }) {
247                 if ($r == -1) {
248                         $logger->warn("Proccessing of record $count in set $fingerprint failed.  Skipping this record");
249                         $count++;
250                 }
251
252                 $logger->info("processing record $count");
253
254                 try {
255                         (my $xml = $r->as_xml_record()) =~ s/\n//sog;
256                         $xml =~ s/^<\?xml.+\?\s*>//go;
257                         $xml =~ s/>\s+</></go;
258                         $xml =~ s/\p{Cc}//go;
259                         $xml = $U->entityize($xml);
260                         $xml =~ s/[\x00-\x1f]//go;
261
262                         if ($type eq 'bib') {
263                                 _add_bib_rec( $e, $xml, $queue_id, $purpose, $bib_source ) or return $e->die_event;
264                         } else {
265                                 _add_auth_rec( $e, $xml, $queue_id, $purpose ) or return $e->die_event;
266                         }
267                         $client->respond($count) if (++$count % 10) == 0;
268                 } catch Error with {
269                         my $error = shift;
270                         $logger->warn("Encountered a bad record at Vandelay ingest: ".$error);
271                 }
272         }
273
274         $e->commit;
275     unlink($filename);
276     $cache->delete_cache('vandelay_import_spool_' . $fingerprint);
277         return undef;
278 }
279
280 __PACKAGE__->register_method(  
281         api_name        => "open-ils.vandelay.bib.process_spool",
282         method          => "process_spool",
283         api_level       => 1,
284         argc            => 3,
285         record_type     => 'bib'
286 );                      
287 __PACKAGE__->register_method(  
288         api_name        => "open-ils.vandelay.auth.process_spool",
289         method          => "process_spool",
290         api_level       => 1,
291         argc            => 3,
292         record_type     => 'auth'
293 );                      
294
295
296 __PACKAGE__->register_method(  
297         api_name        => "open-ils.vandelay.bib_queue.records.retrieve",
298         method          => 'retrieve_queued_records',
299         api_level       => 1,
300         argc            => 2,
301     stream      => 1,
302         record_type     => 'bib'
303 );
304 __PACKAGE__->register_method(  
305         api_name        => "open-ils.vandelay.auth_queue.records.retrieve",
306         method          => 'retrieve_queued_records',
307         api_level       => 1,
308         argc            => 2,
309     stream      => 1,
310         record_type     => 'auth'
311 );
312
313 __PACKAGE__->register_method(  
314         api_name        => "open-ils.vandelay.bib_queue.records.matches.retrieve",
315         method          => 'retrieve_queued_records',
316         api_level       => 1,
317         argc            => 2,
318     stream      => 1,
319         record_type     => 'bib',
320     signature   => {
321         desc => q/Only retrieve queued bib records that have matches against existing records/
322     }
323 );
324 __PACKAGE__->register_method(  
325         api_name        => "open-ils.vandelay.auth_queue.records.matches.retrieve",
326         method          => 'retrieve_queued_records',
327         api_level       => 1,
328         argc            => 2,
329     stream      => 1,
330         record_type     => 'auth',
331     signature   => {
332         desc => q/Only retrieve queued authority records that have matches against existing records/
333     }
334
335 );
336
337 sub retrieve_queued_records {
338     my($self, $conn, $auth, $queue_id, $options) = @_;
339     my $e = new_editor(authtoken => $auth);
340     return $e->event unless $e->checkauth;
341     $options ||= {};
342     my $limit = $$options{limit} || 20;
343     my $offset = $$options{offset} || 0;
344
345     my $type = $self->{record_type};
346     my $queue;
347     if($type eq 'bib') {
348         $queue = $e->retrieve_vandelay_bib_queue($queue_id) or return $e->die_event;
349     } else {
350         $queue = $e->retrieve_vandelay_authority_queue($queue_id) or return $e->die_event;
351     }
352     my $evt = check_queue_perms($e, $type, $queue);
353     return $evt if $evt;
354
355     my $class = ($type eq 'bib') ? 'vqbr' : 'vqar';
356     my $search = ($type eq 'bib') ? 
357         'search_vandelay_queued_bib_record' : 'search_vandelay_queued_authority_record';
358     my $retrieve = ($type eq 'bib') ? 
359         'retrieve_vandelay_queued_bib_record' : 'retrieve_vandelay_queued_authority_record';
360
361     my $filter = ($$options{non_imported}) ? {import_time => undef} : {};
362
363     my $record_ids;
364     if($self->api_name =~ /matches/) {
365         # fetch only matched records
366         $record_ids = queued_records_with_matches($e, $type, $queue_id, $limit, $offset, $filter);
367     } else {
368         # fetch all queue records
369         $record_ids = $e->$search([
370                 {queue => $queue_id, %$filter}, 
371                 {order_by => {$class => 'id'}, limit => $limit, offset => $offset}
372             ],
373             {idlist => 1}
374         );
375     }
376
377
378     for my $rec_id (@$record_ids) {
379         my $params = {   
380             flesh => 1,
381             flesh_fields => {$class => ['attributes', 'matches']},
382         };
383         my $rec = $e->$retrieve([$rec_id, $params]);
384         $rec->clear_marc if $$options{clear_marc};
385         $conn->respond($rec);
386     }
387     return undef;
388 }
389
390 sub check_queue_perms {
391     my($e, $type, $queue) = @_;
392         if ($type eq 'bib') {
393                 return $e->die_event unless
394                         ($e->allowed('CREATE_BIB_IMPORT_QUEUE', undef, $queue) ||
395                          $e->allowed('CREATE_BIB_IMPORT_QUEUE'));
396         } else {
397                 return $e->die_event unless
398                         ($e->allowed('CREATE_AUTHORITY_IMPORT_QUEUE', undef, $queue) ||
399                          $e->allowed('CREATE_AUTHORITY_IMPORT_QUEUE'));
400         }
401
402     return undef;
403 }
404
405 __PACKAGE__->register_method(  
406         api_name        => "open-ils.vandelay.bib_record.list.import",
407         method          => 'import_record_list',
408         api_level       => 1,
409         argc            => 2,
410     stream      => 1,
411         record_type     => 'bib'
412 );
413
414 __PACKAGE__->register_method(  
415         api_name        => "open-ils.vandelay.auth_record.list.import",
416         method          => 'import_record_list',
417         api_level       => 1,
418         argc            => 2,
419     stream      => 1,
420         record_type     => 'auth'
421 );
422
423 sub import_record_list {
424     my($self, $conn, $auth, $rec_ids, $args) = @_;
425     my $e = new_editor(authtoken => $auth);
426     return $e->event unless $e->checkauth;
427     $args ||= {};
428     my $err = import_record_list_impl($self, $conn, $rec_ids, $e->requestor, $args);
429     return $err if $err;
430     return {complete => 1};
431 }
432
433
434 __PACKAGE__->register_method(  
435         api_name        => "open-ils.vandelay.bib_queue.import",
436         method          => 'import_queue',
437         api_level       => 1,
438         argc            => 2,
439     stream      => 1,
440         record_type     => 'bib'
441 );
442
443 __PACKAGE__->register_method(  
444         api_name        => "open-ils.vandelay.auth_queue.import",
445         method          => 'import_queue',
446         api_level       => 1,
447         argc            => 2,
448     stream      => 1,
449         record_type     => 'auth'
450 );
451 __PACKAGE__->register_method(  
452         api_name        => "open-ils.vandelay.bib_queue.nomatch.import",
453         method          => 'import_queue',
454         api_level       => 1,
455         argc            => 2,
456     stream      => 1,
457     signature   => {
458         desc => q/Only import records that have no collisions/
459     },
460         record_type     => 'bib'
461 );
462
463 __PACKAGE__->register_method(  
464         api_name        => "open-ils.vandelay.auth_queue.nomatch.import",
465         method          => 'import_queue',
466         api_level       => 1,
467         argc            => 2,
468     stream      => 1,
469     signature   => {
470         desc => q/Only import records that have no collisions/
471     },
472         record_type     => 'auth'
473 );
474 sub import_queue {
475     my($self, $conn, $auth, $q_id, $options) = @_;
476     my $e = new_editor(authtoken => $auth);
477     return $e->event unless $e->checkauth;
478     $options ||= {};
479     my $type = $self->{record_type};
480     my $class = ($type eq 'bib') ? 'vqbr' : 'vqar';
481
482     my $query = {queue => $q_id, import_time => undef};
483
484     if($self->api_name =~ /nomatch/) {
485         my $matched_recs = queued_records_with_matches($e, $type, $q_id, undef, undef, {import_time => undef});
486         $query->{id} = {'not in' => $matched_recs} if @$matched_recs;
487     }
488
489     my $search = ($type eq 'bib') ? 
490         'search_vandelay_queued_bib_record' : 'search_vandelay_queued_authority_record';
491     my $rec_ids = $e->$search($query, {idlist => 1});
492     my $err = import_record_list_impl($self, $conn, $rec_ids, $e->requestor, $options);
493     return $err if $err;
494     return {complete => 1};
495 }
496
497
498 # returns a list of queued record IDs for a given queue that 
499 # have at least one entry in the match table
500 sub queued_records_with_matches {
501     my($e, $type, $q_id, $limit, $offset, $filter) = @_;
502
503     my $match_class = 'vbm';
504     my $rec_class = 'vqbr';
505     if($type eq 'auth') {
506         $match_class = 'vam';
507          $rec_class = 'vqar';
508     }
509
510     $filter ||= {};
511     $filter->{queue} = $q_id;
512
513     my $query = {
514         distinct => 1, 
515         select => {$match_class => ['queued_record']}, 
516         from => {
517             $match_class => {
518                 $rec_class => {
519                     field => 'id',
520                     fkey => 'queued_record',
521                     filter => $filter,
522                 }
523             }
524         }
525     };        
526
527     if($limit or defined $offset) {
528         $limit ||= 20;
529         $offset ||= 0;
530         $query->{limit} = $limit;
531         $query->{offset} = $offset;
532     }
533
534     my $data = $e->json_query($query);
535     return [ map {$_->{queued_record}} @$data ];
536 }
537
538 sub import_record_list_impl {
539     my($self, $conn, $rec_ids, $requestor, $args) = @_;
540
541     my $overlay_map = $args->{overlay_map} || {};
542     my $type = $self->{record_type};
543     my $total = @$rec_ids;
544     my $count = 0;
545     my %queues;
546     my @ingest_queue;
547
548     my $ingest_ses = OpenSRF::AppSession->connect('open-ils.ingest');
549
550     for my $rec_id (@$rec_ids) {
551
552         my $overlay_target = $overlay_map->{$rec_id};
553
554         my $e = new_editor(xact => 1);
555         $e->requestor($requestor);
556
557         if($type eq 'bib') {
558
559             my $rec = $e->retrieve_vandelay_queued_bib_record($rec_id) ;
560             unless($rec) {
561                 $conn->respond({total => $total, progress => ++$count, imported => $rec_id, err_event => $e->die_event});
562                 $e->rollback;
563                 next;
564             }
565
566             if($rec->import_time) {
567                 $e->rollback;
568                 next;
569             }
570
571             $queues{$rec->queue} = 1;
572
573             my $record;
574             if(defined $overlay_target) {
575                 $logger->info("vl: overlaying record $overlay_target");
576                 $record = OpenILS::Application::Cat::BibCommon->biblio_record_replace_marc(
577                     $e, $overlay_target, $rec->marc); #$rec->bib_source
578             } else {
579                 $logger->info("vl: importing new record");
580                 $record = OpenILS::Application::Cat::BibCommon->biblio_record_xml_import(
581                     $e, $rec->marc); #$rec->bib_source
582             }
583
584             if($U->event_code($record)) {
585                 $conn->respond({total => $total, progress => ++$count, imported => $rec_id, err_event => $record});
586                 $e->rollback;
587                 next;
588             }
589             $rec->imported_as($record->id);
590             $rec->import_time('now');
591
592             unless($e->update_vandelay_queued_bib_record($rec)) {
593                 $conn->respond({total => $total, progress => ++$count, imported => $rec_id, err_event => $e->die_event});
594                 $e->rollback;
595                 next;
596             }
597
598             $e->commit;
599             # XXX handled by the db now
600             #push @ingest_queue, { req => $ingest_ses->request('open-ils.ingest.full.biblio.record', $record->id), rec_id => $record->id };
601
602         } else { # authority
603
604             my $rec = $e->retrieve_vandelay_queued_authority_record($rec_id);
605             unless($rec) {
606                 $conn->respond({total => $total, progress => ++$count, imported => $rec_id, err_event => $e->die_event});
607                 $e->rollback;
608                 next;
609             }
610
611             if($rec->import_time) {
612                 $e->rollback;
613                 next;
614             }
615
616             $queues{$rec->queue} = 1;
617
618             my $record;
619             if(defined $overlay_target) {
620                 $logger->info("vl: overlaying record $overlay_target");
621                 $record = OpenILS::Application::Cat::AuthCommon->overlay_authority_record(
622                     $overlay_target, $rec->marc); #$source);
623             } else {
624                 $logger->info("vl: importing new record");
625                 $record = OpenILS::Application::Cat::AuthCommon->import_authority_record(
626                     $e, $rec->marc) #$source);
627             }
628
629             if($U->event_code($record)) {
630                 $conn->respond({total => $total, progress => ++$count, imported => $rec_id, err_event => $record});
631                 $e->rollback;
632                 next;
633             }
634
635             $rec->imported_as($record->id);
636             $rec->import_time('now');
637             unless($e->update_vandelay_queued_authority_record($rec)) {
638                 $conn->respond({total => $total, progress => ++$count, imported => $rec_id, err_event => $e->die_event});
639                 $e->rollback;
640                 next;
641             }
642
643             $e->commit;
644             push @ingest_queue, { req => $ingest_ses->request('open-ils.ingest.full.authority.record', $record->id), rec_id => $record->id };
645         }
646
647         $conn->respond({total => $total, progress => $count, imported => $rec_id}) if (++$count % 10) == 0;
648     }
649
650     # see if we need to mark any queues as complete
651     my $e = new_editor(xact => 1);
652     for my $q_id (keys %queues) {
653         if($type eq 'bib') {
654             my $remaining = $e->search_vandelay_queued_bib_record(
655                 [{queue => $q_id, import_time => undef}, {limit =>1}], {idlist => 1});
656             unless(@$remaining) {
657                 my $queue = $e->retrieve_vandelay_bib_queue($q_id);
658                 unless($U->is_true($queue->complete)) {
659                     $queue->complete('t');
660                     $e->update_vandelay_bib_queue($queue) or return $e->die_event;
661                     $e->commit;
662                     last
663                 }
664             }
665         } else {
666             my $remaining = $e->search_vandelay_queued_authority_record(
667                 [{queue => $q_id, import_time => undef}, {limit =>1}], {idlist => 1});
668             unless(@$remaining) {
669                 my $queue = $e->retrieve_vandelay_authority_queue($q_id);
670                 unless($U->is_true($queue->complete)) {
671                     $queue->complete('t');
672                     $e->update_vandelay_authority_queue($queue) or return $e->die_event;
673                     $e->commit;
674                     last
675                 }
676             }
677         }
678     }
679     $e->rollback;
680
681     $count = 0;
682     for my $ingest (@ingest_queue) {
683         try { $ingest->{req}->gather(1); } otherwise {};
684         $conn->respond({total => $total, progress => $count, imported => $ingest->{rec_id}}) if (++$count % 10) == 0;
685     } 
686
687     $ingest_ses->disconnect();
688     return undef;
689 }
690
691
692 __PACKAGE__->register_method(  
693         api_name        => "open-ils.vandelay.bib_queue.owner.retrieve",
694         method          => 'owner_queue_retrieve',
695         api_level       => 1,
696         argc            => 2,
697     stream      => 1,
698         record_type     => 'bib'
699 );
700 __PACKAGE__->register_method(  
701         api_name        => "open-ils.vandelay.authority_queue.owner.retrieve",
702         method          => 'owner_queue_retrieve',
703         api_level       => 1,
704         argc            => 2,
705     stream      => 1,
706         record_type     => 'auth'
707 );
708
709 sub owner_queue_retrieve {
710     my($self, $conn, $auth, $owner_id, $filters) = @_;
711     my $e = new_editor(authtoken => $auth);
712     return $e->die_event unless $e->checkauth;
713     $owner_id = $e->requestor->id; # XXX add support for viewing other's queues?
714     my $queues;
715     $filters ||= {};
716     my $search = {owner => $owner_id};
717     $search->{$_} = $filters->{$_} for keys %$filters;
718
719     if($self->{record_type} eq 'bib') {
720         $queues = $e->search_vandelay_bib_queue(
721             [$search, {order_by => {vbq => 'lower(name)'}}]);
722     } else {
723         $queues = $e->search_vandelay_authority_queue(
724             [$search, {order_by => {vaq => 'lower(name)'}}]);
725     }
726     $conn->respond($_) for @$queues;
727     return undef;
728 }
729
730 __PACKAGE__->register_method(  
731         api_name        => "open-ils.vandelay.bib_queue.delete",
732         method          => "delete_queue",
733         api_level       => 1,
734         argc            => 2,
735         record_type     => 'bib'
736 );            
737 __PACKAGE__->register_method(  
738         api_name        => "open-ils.vandelay.auth_queue.delete",
739         method          => "delete_queue",
740         api_level       => 1,
741         argc            => 2,
742         record_type     => 'auth'
743 );  
744
745 sub delete_queue {
746     my($self, $conn, $auth, $q_id) = @_;
747     my $e = new_editor(xact => 1, authtoken => $auth);
748     return $e->die_event unless $e->checkauth;
749     if($self->{record_type} eq 'bib') {
750             return $e->die_event unless $e->allowed('CREATE_BIB_IMPORT_QUEUE');
751         my $queue = $e->retrieve_vandelay_bib_queue($q_id)
752             or return $e->die_event;
753         $e->delete_vandelay_bib_queue($queue)
754             or return $e->die_event;
755     } else {
756             return $e->die_event unless $e->allowed('CREATE_AUTHORITY_IMPORT_QUEUE');
757         my $queue = $e->retrieve_vandelay_authority_queue($q_id)
758             or return $e->die_event;
759         $e->delete_vandelay_authority_queue($queue)
760             or return $e->die_event;
761     }
762     $e->commit;
763     return 1;
764 }
765
766
767 __PACKAGE__->register_method(  
768         api_name        => "open-ils.vandelay.queued_bib_record.html",
769         method          => 'queued_record_html',
770         api_level       => 1,
771         argc            => 2,
772     stream      => 1,
773         record_type     => 'bib'
774 );
775 __PACKAGE__->register_method(  
776         api_name        => "open-ils.vandelay.queued_authority_record.html",
777         method          => 'queued_record_html',
778         api_level       => 1,
779         argc            => 2,
780     stream      => 1,
781         record_type     => 'auth'
782 );
783
784 sub queued_record_html {
785     my($self, $conn, $auth, $rec_id) = @_;
786     my $e = new_editor(authtoken => $auth);
787     return $e->event unless $e->checkauth;
788     my $rec;
789     if($self->{record_type} eq 'bib') {
790         $rec = $e->retrieve_vandelay_queued_bib_record($rec_id)
791             or return $e->event;
792     } else {
793         $rec = $e->retrieve_vandelay_queued_authority_record($rec_id)
794             or return $e->event;
795     }
796
797     return $U->simplereq(
798         'open-ils.search',
799         'open-ils.search.biblio.record.html', undef, 1, $rec->marc);
800 }
801
802
803 __PACKAGE__->register_method(  
804         api_name        => "open-ils.vandelay.bib_queue.summary.retrieve", 
805         method          => 'retrieve_queue_summary',
806         api_level       => 1,
807         argc            => 2,
808     stream      => 1,
809         record_type     => 'bib'
810 );
811 __PACKAGE__->register_method(  
812         api_name        => "open-ils.vandelay.auth_queue.summary.retrieve",
813         method          => 'retrieve_queue_summary',
814         api_level       => 1,
815         argc            => 2,
816     stream      => 1,
817         record_type     => 'auth'
818 );
819
820 sub retrieve_queue_summary {
821     my($self, $conn, $auth, $queue_id) = @_;
822     my $e = new_editor(authtoken => $auth);
823     return $e->event unless $e->checkauth;
824
825     my $queue;
826     my $type = $self->{record_type};
827     if($type eq 'bib') {
828         $queue = $e->retrieve_vandelay_bib_queue($queue_id)
829             or return $e->event;
830     } else {
831         $queue = $e->retrieve_vandelay_authority_queue($queue_id)
832             or return $e->event;
833     }
834
835     my $evt = check_queue_perms($e, $type, $queue);
836     return $evt if $evt;
837
838     my $search = 'search_vandelay_queued_bib_record';
839     $search =~ s/bib/authority/ if $type ne 'bib';
840
841     return {
842         queue => $queue,
843         total => scalar(@{$e->$search({queue => $queue_id}, {idlist=>1})}),
844         imported => scalar(@{$e->$search({queue => $queue_id, import_time => {'!=' => undef}}, {idlist=>1})}),
845     };
846 }
847
848
849 __PACKAGE__->register_method(  
850         api_name        => "open-ils.vandelay.bib_record.list.asset.import",
851         method          => 'import_record_list_assets',
852         api_level       => 1,
853         argc            => 2,
854     stream      => 1,
855         record_type     => 'bib'
856 );
857 __PACKAGE__->register_method(  
858         api_name        => "open-ils.vandelay.bib_record.queue.asset.import",
859         method          => 'import_record_queue_assets',
860         api_level       => 1,
861         argc            => 2,
862     stream      => 1,
863         record_type     => 'bib'
864 );
865
866 sub import_record_list_assets {
867     my($self, $conn, $auth, $import_def, $rec_ids) = @_;
868     my $e = new_editor(authtoken => $auth);
869     return $e->event unless $e->checkauth;
870     my $err = import_record_asset_list_impl($conn, $import_def, $rec_ids, $e->requestor);
871     return $err if $err;
872     return {complete => 1};
873 }
874
875 sub import_record_queue_assets {
876     my($self, $conn, $auth, $import_def, $q_id) = @_;
877     my $e = new_editor(authtoken => $auth);
878     return $e->event unless $e->checkauth;
879     my $rec_ids = $e->search_vandelay_queued_bib_record(
880         {queue => $q_id, import_time => {'!=' => undef}}, {idlist => 1});
881     my $err = import_record_asset_list_impl($conn, $import_def, $rec_ids, $e->requestor);
882     return $err if $err;
883     return {complete => 1};
884 }
885
886 # --------------------------------------------------------------------------------
887 # Given a list of queued record IDs, imports all items attached to those records
888 # --------------------------------------------------------------------------------
889 sub import_record_asset_list_impl {
890     my($conn, $import_def, $rec_ids, $requestor) = @_;
891
892     my $total = @$rec_ids;
893     my $try_count = 0;
894     my $in_count = 0;
895     my $roe = new_editor(requestor => $requestor);
896
897     for my $rec_id (@$rec_ids) {
898         my $rec = $roe->retrieve_vandelay_queued_bib_record($rec_id);
899         next unless $rec and $rec->import_time;
900         my $item_ids = $roe->search_vandelay_import_item({definition => $import_def, record => $rec->id}, {idlist=>1});
901
902         for my $item_id (@$item_ids) {
903             my $e = new_editor(requestor => $requestor, xact => 1);
904             my $item = $e->retrieve_vandelay_import_item($item_id);
905             $try_count++;
906
907             # --------------------------------------------------------------------------------
908             # Find or create the volume
909             # --------------------------------------------------------------------------------
910             my ($vol, $evt) =
911                 OpenILS::Application::Cat::AssetCommon->find_or_create_volume(
912                     $e, $item->call_number, $rec->imported_as, $item->owning_lib);
913
914             if($evt) {
915                 respond_with_status($conn, $total, $try_count, $in_count, $evt);
916                 $e->rollback;
917                 next;
918             }
919
920             # --------------------------------------------------------------------------------
921             # Create the new copy
922             # --------------------------------------------------------------------------------
923             my $copy = Fieldmapper::asset::copy->new;
924             $copy->loan_duration(2);
925             $copy->fine_level(2);
926             $copy->barcode($item->barcode);
927             $copy->location($item->location);
928             $copy->circ_lib($item->circ_lib || $item->owning_lib);
929             $copy->status($item->status || OILS_COPY_STATUS_IN_PROCESS);
930             $copy->circulate($item->circulate);
931             $copy->deposit($item->deposit);
932             $copy->deposit_amount($item->deposit_amount);
933             $copy->ref($item->ref);
934             $copy->holdable($item->holdable);
935             $copy->price($item->price);
936             $copy->circ_as_type($item->circ_as_type);
937             $copy->alert_message($item->alert_message);
938             $copy->opac_visible($item->opac_visible);
939             $copy->circ_modifier($item->circ_modifier);
940
941             # --------------------------------------------------------------------------------
942             # see if a valid circ_modifier was provided
943             # --------------------------------------------------------------------------------
944             #if($copy->circ_modifier and not $e->retrieve_config_circ_modifier($item->circ_modifier)) {
945             if($copy->circ_modifier and not $e->search_config_circ_modifier({code=>$item->circ_modifier})->[0]) {
946                 respond_with_status($conn, $total, $try_count, $in_count, $e->die_event);
947                 $e->rollback;
948                 next;
949             }
950
951             if($evt = OpenILS::Application::Cat::AssetCommon->create_copy($e, $vol, $copy)) {
952                 $e->rollback;
953                 respond_with_status($conn, $total, $try_count, $in_count, $evt);
954                 next;
955             }
956
957             # --------------------------------------------------------------------------------
958             # create copy notes
959             # --------------------------------------------------------------------------------
960             $evt = OpenILS::Application::Cat::AssetCommon->create_copy_note(
961                 $e, $copy, '', $item->pub_note, 1) if $item->pub_note;
962
963             if($evt) {
964                 respond_with_status($conn, $total, $try_count, $in_count, $evt);
965                 $e->rollback;
966                 next;
967             }
968
969             $evt = OpenILS::Application::Cat::AssetCommon->create_copy_note(
970                 $e, $copy, '', $item->priv_note, 1) if $item->priv_note;
971
972             if($evt) {
973                 respond_with_status($conn, $total, $try_count, $in_count, $evt);
974                 $e->rollback;
975                 next;
976             }
977
978             # --------------------------------------------------------------------------------
979             # Item import succeeded
980             # --------------------------------------------------------------------------------
981             $e->commit;
982             respond_with_status($conn, $total, $try_count, ++$in_count, undef, imported_as => $copy->id);
983         }
984     }
985     return undef;
986 }
987
988
989 sub respond_with_status {
990     my($conn, $total, $try_count, $success_count, $err, %args) = @_;
991     $conn->respond({
992         total => $total, 
993         progress => $try_count, 
994         err_event => $err, 
995         success_count => $success_count, %args }) if $err or ($try_count % 5 == 0);
996 }
997
998
999 1;